使用 Delphi 和 TIdHttp 将数据发布到 ASP .NET 页面

发布于 2024-08-03 11:32:22 字数 2455 浏览 2 评论 0 原文

我有一个像这样简单的 Asp .net 页面 http://issamsoft.com/app2/page1.aspx 我想向其发布一些数据并从响应中提取数据, 通过使用 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;

但 TIdhttp 总是给出错误(HTTP/1.1 500 Internal Server Error.) 我在 idHttp 单元中读到了一些关于 http 协议 v 1.1 问题的评论,如下所示:

目前,当发出 POST 时,IdHTTP 会自动将协议设置为版本 1.0 独立于它最初的值,这是因为 有些服务器并不完全遵守 RFC。在 特别是,他们不尊重发送/不发送 Expect: 100-Continue 标头。在我们找到不破坏 RFC 的最佳解决方案之前,我们 将把 POSTS 限制为 1.0 版本。

我的代码有问题还是 TidHttp Bug?如果问题出在 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);
    } 

我在哪里可以找到像 Delphi 中的 WebClient 这样的(好的/可信的)类?免费首选:)

编辑: 我希望 VIEWSTATE,EVENTVALIDATION 的机制对你来说足够清楚,它们是服务器生成的哈希值,它们可能会改变(已经改变),我原来的项目有一段代码只是为了提取当前的 VIEWSTATE,EVENTVALIDATION 值,但我省略该部分只是为了使我的示例简单明了,因此当您想尝试上述代码时,您必须从当前页面源获取 VIEWSTATE,EVENTVALIDATION 值。

I have an Asp .net page like this simple one http://issamsoft.com/app2/page1.aspx
and I want to post to it some data and extract data from the response,
by using TIdHttp. I tried to do that in Delphi2009 like this:

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;

but TIdhttp always gives an error(HTTP/1.1 500 Internal Server Error.)
I read some comments in the idHttp unit talks about problems with http protocol v 1.1 like this one:

Currently when issuing a POST, IdHTTP will automatically set the protocol to version
1.0 independently of the value it had initially, This is because
there are some servers that don't respect the RFC to the full extent. In
particular, they don't respect sending/not sending the Expect: 100-Continue
header. Until we find an optimum solution that does NOT break the RFC, we
will restrict POSTS to version 1.0.

is there something wrong with my code or it's TidHttp Bug? and if the problem is in
TIdHttp, is there any workaround? or is there other solution using Indy components?

besides. I've made a solution in C# using WebClient and it works very good.

        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);
    } 

where i can find (good/trusted) class like WebClient in Delphi? free preferred :)

Edit:
I hope mechanism of VIEWSTATE,EVENTVALIDATION is clear enough for you, they are hash values generated by server, and they may change(already changed), my orginal project has a piece of code just to extract the current VIEWSTATE,EVENTVALIDATION values, but I omit that part just to make my example simple and clear, so when you want to try the above code you must take VIEWSTATE,EVENTVALIDATION values from the current page source.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

反差帅 2024-08-10 11:32:22

这很可能是由于在 C# 中,您使用与号 (&) 字符来连接 VIEWSTATE、EVENTVALIDATION 和 FORMPARAMS 造成的。

但在 Delphi 中,您使用 TStringList 和 Add。
Add 不会在加法之间放置一个 & 符号 (&),而是放置一个 CR+LF。

因此,您在 Delphi 中发送的数据与 C# 中发送的数据不同。

如果您更改 Delphi 中的字符串连接逻辑以匹配 C# 中的逻辑,则无论您在 Delphi 端使用哪种 WebClient,它都应该有效。

--jeroen

编辑:20090830

此代码有效;使用 Fiddler2 检查 C# 和 IE7 输出,我发现您还需要转义“/”和“=”字符。

Edit2: 20090831

不知何故,网站上的 VIEWSTATE 和 EVENTVALIDATION 自昨天以来发生了变化(尽管我不确定为什么)。我已经更改了代码,并且在发布我对此答案的更改时它可以工作。
这是从 Internet Explorer 7 中发布页面时每个 Fiddler 捕获的新请求内容:

__VIEWSTATE=%2FwEPDwUKMjA3NjE4MDczNmRk5%2FC2iWwvlAB3L1wYzRpm3KZhRC0%3D&__EVENTVALIDATION=%2FwEWAwLXzuATAuzRsusGAoznisYGSYOqDGy4vMunY6A8xi6ahQEPI5Q%3D&TextBox1=Issam&Button1=Button

这是从 Delphi 示例发布时的新请求:

__VIEWSTATE=%2FwEPDwUKMjA3NjE4MDczNmRk5%2FC2iWwvlAB3L1wYzRpm3KZhRC0%3D&__EVENTVALIDATION=%2FwEWAwLXzuATAuzRsusGAoznisYGSYOqDGy4vMunY6A8xi6ahQEPI5Q%3D&TextBox1=Issam&Button1=Button

下面的示例现在给出了此结果(请注意“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>

Edit3: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.

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.

这应该可以帮助您继续。

——杰罗恩

This is most likely caused by the fact that in C#, you use an ampersand (&) characters to concatenate the VIEWSTATE, EVENTVALIDATION and FORMPARAMS.

But in Delphi, you use a TStringList and Add.
Add will not put an ampersand (&), but a CR+LF between the additions.

Hence you are sending different data in Delphi than in C#.

If you change your string concatenation logic in Delphi to match the logic in C#, it should work, not matter what kind of WebClient you use on the Delphi side.

--jeroen

Edit: 20090830

This code works; inspecting the C# and IE7 output using Fiddler2, I found out you also need to escape the '/' and '=' characters.

Edit2: 20090831

Somehow the VIEWSTATE and EVENTVALIDATION on the site have changed since yesterday (though I'm not sure why). I have changed the code, and it works at the time of posting my changes to this answer.
This is the new request content as captured per Fiddler when posting the page from within Internet Explorer 7:

__VIEWSTATE=%2FwEPDwUKMjA3NjE4MDczNmRk5%2FC2iWwvlAB3L1wYzRpm3KZhRC0%3D&__EVENTVALIDATION=%2FwEWAwLXzuATAuzRsusGAoznisYGSYOqDGy4vMunY6A8xi6ahQEPI5Q%3D&TextBox1=Issam&Button1=Button

This is the new request as when posted form the Delphi example:

__VIEWSTATE=%2FwEPDwUKMjA3NjE4MDczNmRk5%2FC2iWwvlAB3L1wYzRpm3KZhRC0%3D&__EVENTVALIDATION=%2FwEWAwLXzuATAuzRsusGAoznisYGSYOqDGy4vMunY6A8xi6ahQEPI5Q%3D&TextBox1=Issam&Button1=Button

The below sample now gives this result (note the "Issam" in the result):

<!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>

Edit3: 20090831

And indeed the VIEWSTATE and EVENTVALIDATION changed again: somehow they keep changing: there seems to be a time factor involved.

So I adapted the code, now it it can extract the VIEWSTATE and EVENTVALIDATION from a GET request, then put that into a POST request.

In addition, it appeared that the '+' and ':' also needs to be escaped.
So I dug into the ASP.NET page generation logic, found out that they use HttpUtility.UrlEncode to do the escaping, which ultimately checks HttpUtility.IsSafe which characters to escape.
So I adapted took the Reflector reverse engineerd Delphi code into a THttpUtility class.

This is the final code:

{$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.

And the THttpUtlity class:

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.

This should get you going.

--jeroen

因为看清所以看轻 2024-08-10 11:32:22

如果您在 TIdHTTP 实例 HTTPOptions 属性中包含 hoKeepOrigProtocol 选项,则它不会回退到 HTTP 1.0。

这记录在您引用的评论文本下方的几行:)

    // If hoKeepOrigProtocol is SET, is possible to assume that the developer
    // is sure in operations of the server
    if not (hoKeepOrigProtocol in FOptions) then begin
      FProtocolVersion := pv1_0;
    end;

If you include the hoKeepOrigProtocol option in the TIdHTTP instance HTTPOptions property, it will not fall back to HTTP 1.0.

This is documented some lines below the comment text which you cited :)

    // If hoKeepOrigProtocol is SET, is possible to assume that the developer
    // is sure in operations of the server
    if not (hoKeepOrigProtocol in FOptions) then begin
      FProtocolVersion := pv1_0;
    end;
彻夜缠绵 2024-08-10 11:32:22

您需要更新 VIEWSTATE 和 EVENTVALIDATION 值。

运行该代码会导致 500 错误,但如果我打开页面并使用网页源中的新 __VIEWSTATE 和 __EVENTVALIDATION 值,则不会再导致 500 错误。

我不知道为什么 C# 客户端可以工作,而 Delphi 客户端却不能,但也许它不再工作了?

这看起来像是 ASP 问题,而不是 Delphi 问题。 Indy (TIdHTTP) 和 Synapse 都是很好的 Delphi 套接字库。

You need to update the VIEWSTATE and EVENTVALIDATION values.

Running that code causes a 500 error, but if I open the page and use the new __VIEWSTATE and __EVENTVALIDATION values from the webpage source, it no longer causes a 500 error.

I don't know why a C# client would have worked when the Delphi one didn't, but maybe it doesn't work anymore?

This looks like an ASP issue, not Delphi. Both Indy (TIdHTTP) and Synapse are good socket libraries for Delphi.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文