Как отправить данные POST с помощью TW3HttpRequest

Поэтому я начал играть с помощью SMS и попытался создать программу (ярлык и кнопку), чтобы попасть на веб-сайт с запросом на публикацию и отобразить результат.

У меня нет проблем с подсказками / предупреждениями / ошибками, и все выглядит хорошо для меня. Следующий код представляет собой переделку пары существующих примеров, соединенных вместе.

procedure TForm1.ExecuteCmd;
var
  whttp : TW3HttpRequest;
  wParams : string;
begin
  wHttp := TW3HttpRequest.Create;
  try

    whttp.OnDataReady := lambda (Sender)
      if (w3Label1.caption = '') then
        w3Label1.caption := wHttp.ResponseText;
    end;

    whttp.OnReadyStateChange := lambda (Sender)
      if (wHttp.ReadyState = 4) and (wHttp.Status = 200) then
      begin
        if (w3Label1.caption = '') then
          w3Label1.caption := wHttp.ResponseText;
      end;
    end;

    wParams := 'cmd=TestID1';
    whttp.open('POST','http://www.server1.com/executecmd.php');
    whttp.RequestHeaders['Content-type'] := 'application/x-www-form-urlencoded';
    whttp.Send(wParams);
  finally
    wHttp.free;
  end;
end;

procedure TForm1.W3Button1Click(Sender: TObject);
begin
  ExecuteCmd;
end;

Проблема в том, что когда я фактически нажимаю кнопку, я получаю следующее сообщение об ошибке: Uncaught TypeError: Невозможно прочитать свойство 'readyState' из null [строка #6277]

Ошибка в автоматически сгенерированном коде и, похоже, не имеет отношения к тому, что я написал специально. Если я уберу все ссылки на ReadyState из своего кода, я все равно получу ошибку.

Что мне не хватает? Я чувствую, что это как-то связано с лямбда-функциями.

1 ответ

Решение

Ваша проблема в том, что вы ожидаете whttp.Send блокировать. Send, как его эквивалент JavaScript, является асинхронным. Перед POST может даже выполнить, whttp объект освобожден (в finally блок). Когда обратный звонок (OnReadyStateChanged) называется, whttp был уже освобожден (и теперь является нулевым), а затем вы пытаетесь позвонить ReadyState на этом освобожденном (нулевом) объекте.

Еще одна причина путаницы в том, что object.Free в Delphi для Windows/OS X уничтожает объект, в то время как в Smart он просто устанавливает object ссылка на nil и оставляет уничтожение для сборки мусора JavaScript. Вот почему whttp все еще жив после Free и почему OnReadyStateChanged называется вообще.

Это отлично работает:

uses 
  W3System, W3Graphics, W3Components, W3Forms, W3Fonts, W3Borders, W3Application,
  W3Button, W3Inet, W3Memo;

type
  TForm1=class(TW3form)
    procedure W3Button1Click(Sender: TObject);
  private
    {$I 'Form1:intf'}
    whttp: TW3HttpRequest;
  protected
    procedure InitializeForm; override;
    procedure InitializeObject; override;
    procedure Resize; override;
  end;

implementation

{ TForm1}

procedure TForm1.W3Button1Click(Sender: TObject);
var
  wParams: string;
begin
  whttp := TW3HttpRequest.Create;

  whttp.OnReadyStateChange := lambda (Sender)
    if (whttp.ReadyState = 4) and (wHttp.Status = 200) then
    begin
      W3Memo1.Text := wHttp.ResponseText;
      whttp.OnReadyStateChange := nil;
      whttp := nil;
    end;
  end;

  wParams := 'cmd=TestID1';
  whttp.open('POST','http://httpbin.org/post');
  whttp.RequestHeaders['Content-type'] := 'application/x-www-form-urlencoded';
  whttp.Send(wParams);
end;
Другие вопросы по тегам