Какой самый простой способ вызвать URL-адрес Http GET с помощью Delphi?

Есть веб-службы, которые я хочу вызвать в своем приложении, я могу использовать их с импортом WSDL или просто используя «HTTP GET» с URL-адресом и параметрами, поэтому я предпочитаю более позднее, потому что это простая вещь.

Я знаю, что могу использовать indy idhttp.get для выполнения этой работы, но это очень простая вещь, и я не хочу добавлять сложный indy-код в свое приложение.

ОБНОВИТЬ: извините, если я не понял, я имел в виду «не добавлять сложный indy-код», что я не хочу добавлять компоненты indy только для этой простой задачи и предпочитаю более легкий способ для этого.

Как вы думаете, достаточно ли использования HTTP GET для вызова функции веб-сервиса?

Serguzest 19.11.2008 16:13

Это если это веб-сервис RESTful.

Bruce McGee 19.11.2008 16:36

я не знал, что REST тоже может иметь wsdl

Serguzest 19.11.2008 18:38

AhmetCiftci, как я уже говорил, у службы есть URL-адрес «HTTP GET» для ее вызова, поэтому можно использовать WSDL или просто запросить «HTTP GET».

Mohammed Nasman 20.11.2008 13:51
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
44
4
85 938
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

Вызвать веб-службу RESTful с помощью Indy довольно просто.

Добавьте IdHTTP в свой пункт uses. Помните, что IdHTTP нуждается в префиксе «HTTP: //» в ваших URL-адресах.

function GetURLAsString(const aURL: string): string;
var
  lHTTP: TIdHTTP;
begin
  lHTTP := TIdHTTP.Create;
  try
    Result := lHTTP.Get(aURL);
  finally
    lHTTP.Free;
  end;
end;

Вопрос был в том, чтобы не добавлять сложный код Indy. Код несложный.

Bruce McGee 19.11.2008 16:37

Брюс, Ларс прав, я сказал в своих вопросах, что не хочу использовать indyt "idhttp.get", это самый простой способ, но я хотел светлый путь :)

Mohammed Nasman 20.11.2008 13:56

Ваш самый легкий вариант - использовать внешний код, будь то Indy, Synapse или WinINet. Если вы не можете или не хотите использовать компоненты или классы Delphi, используйте функции оболочки Delphi для WinINet. Также внешний, но, по крайней мере, DLL устанавливается вместе с Windows.

Bruce McGee 20.11.2008 14:35

В свою защиту Indy поставляется с Delphi, но версия WinInet и поведение меняются с установленной версией IE, что похоже на ад DLL.

Warren P 03.02.2011 18:08

В моей ситуации добавление idHTTP заставило мой exe прыгнуть с 300 КБ до 2 МБ, что не всегда имеет значение, но в моем случае имело значение.

Toby Allen 09.10.2013 18:24

@Toby: Мне было бы очень любопытно узнать, почему это так. Какая версия Delphi и какое приложение (VCL / Console)?

Bruce McGee 15.11.2013 17:21

@BruceMcGee Я думаю, это был Delphi XE. В Delphi 7 это был небольшой скачок, возможно, примерно до 800K, но в XE он был намного больше. Консольное приложение. Понятия не имею, почему это сделало его намного больше, полагаю, много кода для компиляции.

Toby Allen 17.11.2013 00:35

@Toby: пустое консольное приложение имеет размер 40 КБ в D7 и 83 КБ в DXE. Добавление IdHttp в раздел uses увеличивает их размер до 139 КБ и 739 КБ соответственно. Я не уверен, откуда взялись эти 2 МБ. Похоже, это могла быть более поздняя версия Delphi, скомпилированная в режиме отладки.

Bruce McGee 17.11.2013 04:49
TIdHTTP.Create(nil); можно сократить до TIdHTTP.Create; с помощью Indy 10.6
mjn 30.08.2014 15:57
Ответ принят как подходящий

Вы можете использовать WinINet API так:

uses WinInet;

function GetUrlContent(const Url: string): string;
var
  NetHandle: HINTERNET;
  UrlHandle: HINTERNET;
  Buffer: array[0..1024] of Char;
  BytesRead: dWord;
begin
  Result := '';
  NetHandle := InternetOpen('Delphi 5.x', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);

  if Assigned(NetHandle) then 
  begin
    UrlHandle := InternetOpenUrl(NetHandle, PChar(Url), nil, 0, INTERNET_FLAG_RELOAD, 0);

    if Assigned(UrlHandle) then
      { UrlHandle valid? Proceed with download }
    begin
      FillChar(Buffer, SizeOf(Buffer), 0);
      repeat
        Result := Result + Buffer;
        FillChar(Buffer, SizeOf(Buffer), 0);
        InternetReadFile(UrlHandle, @Buffer, SizeOf(Buffer), BytesRead);
      until BytesRead = 0;
      InternetCloseHandle(UrlHandle);
    end
    else
      { UrlHandle is not valid. Raise an exception. }
      raise Exception.CreateFmt('Cannot open URL %s', [Url]);

    InternetCloseHandle(NetHandle);
  end
  else
    { NetHandle is not valid. Raise an exception }
    raise Exception.Create('Unable to initialize Wininet');
end;

источник: http://www.scalabium.com/faq/dct0080.htm

WinINet API использует то же самое, что и InternetExplorer, поэтому вы также можете бесплатно получить любое соединение и настройки прокси, установленные InternetExplorer.

Как говорит Брюс, если бы у вас был IE, неправильно настроенный для использования, например, неработающего прокси-сервера, вас тоже бы задержали. Непонятно и неприятно, если это случилось.

Warren P 03.02.2011 18:07

На собственном опыте я узнал, что вы также получаете все ошибки в IE wininet.dll, который установлен в вашей клиентской системе, бесплатно, включая ужасную ошибку TIMEOUT. БУДЬТЕ ВНИМАТЕЛЬНЫ.

Warren P 16.06.2011 18:16

@Warren: они исправляются в обновлениях безопасности и пакетах обновлений, в то время как ваш собственный код или кто-либо еще не получает такой же критической оценки со стороны многих глаз.

Dave Van den Eynde 16.08.2011 15:31

И они ломаются. Почему неработающие версии WinInet никогда не исправляются, пока вы не обновитесь до новой версии IE? Ужасный. Не фиксируется в пакете обновления, если сам IE не принудительно загружен в пакет обновления.

Warren P 17.08.2011 01:25

Обратите внимание, что WinInet не следует использовать в службах.

Marc Durdin 16.12.2015 08:21

Обратите внимание, что этот код не учитывает кодировки символов. Он предполагает, что char / string являются 8-битными, и сохраняет необработанные байты ответа как есть в возвращенном string. Тело ответа имеет кодировку, которая указывается / выводится из заголовков ответа HTTP. И string также имеет кодировку, будь то ANSI в D2007 и ранее или UTF-16 в D2009 и позже. Код должен преобразовать данные тела ответа из кодировки ответа в Unicode, а затем из Unicode в собственную кодировку string.

Remy Lebeau 22.06.2018 22:28

Компонент Indy TIdHTTP обрабатывает эти преобразования за вас, когда возвращает тело ответа как string.

Remy Lebeau 22.06.2018 22:29

Используйте функцию Synapse TCP / IP в модуле HTTPSEND (HTTPGetText, HTTPGetBinary). Он будет выполнять HTTP-запрос за вас и не требует никаких внешних DLL, кроме Winsock. Последний выпуск SVN отлично работает в Delphi 2009. В нем используются вызовы функций блокировки, поэтому нет событий для программирования.

Обновление: блоки очень легкие и не состоят из компонентов. Последняя версия от SVN также отлично работает в Delphi XE4.

HTTP-вызовы в Indy также блокируются.

Bruce McGee 19.11.2008 16:55

Если можно загрузить в файл, вы можете использовать TDownloadURL из модуля ExtActns. Намного проще, чем напрямую использовать WinInet.

procedure TMainForm.DownloadFile(URL: string; Dest: string);
var
  dl: TDownloadURL;
begin
  dl := TDownloadURL.Create(self);
  try
    dl.URL := URL;
    dl.FileName := Dest;
    dl.ExecuteTarget(nil); //this downloads the file
  finally
    dl.Free;
  end;
end;

Также можно получать уведомления о прогрессе при использовании этого. Просто назначьте обработчик события событию TDownloadURL OnDownloadProgress.

На самом деле код в принятом ответе у меня не работал. Поэтому я немного изменил его, так что он фактически возвращает String и изящно закрывает все после выполнения. Пример возвращает полученные данные как UTF8String, поэтому он будет хорошо работать как для ASCII, так и для страниц UTF8.

uses WinInet;

function GetUrlContent(const Url: string): UTF8String;
var
  NetHandle: HINTERNET;
  UrlHandle: HINTERNET;
  Buffer: array[0..1023] of byte;
  BytesRead: dWord;
  StrBuffer: UTF8String;
begin
  Result := '';
  NetHandle := InternetOpen('Delphi 2009', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
  if Assigned(NetHandle) then
    try
      UrlHandle := InternetOpenUrl(NetHandle, PChar(Url), nil, 0, INTERNET_FLAG_RELOAD, 0);
      if Assigned(UrlHandle) then
        try
          repeat
            InternetReadFile(UrlHandle, @Buffer, SizeOf(Buffer), BytesRead);
            SetString(StrBuffer, PAnsiChar(@Buffer[0]), BytesRead);
            Result := Result + StrBuffer;
          until BytesRead = 0;
        finally
          InternetCloseHandle(UrlHandle);
        end
      else
        raise Exception.CreateFmt('Cannot open URL %s', [Url]);
    finally
      InternetCloseHandle(NetHandle);
    end
  else
    raise Exception.Create('Unable to initialize Wininet');
end;

Надеюсь, это поможет кому-то вроде меня, который искал простой код для извлечения содержимого страницы в Delphi. Ура, Алдис :)

Это работает, только если ответ действительно закодирован в ASCII или UTF-8, что не является гарантией.

Remy Lebeau 22.06.2018 22:31

Если ваше приложение предназначено только для Windows, я бы предложил использовать WinSock. Он достаточно простой, позволяет выполнять любой HTTP-запрос, может работать как синхронно, так и асинхронно (используя неблокирующий WSASend / WSARecv с обратными вызовами или старый добрый send / recv в выделенном потоке).

Хотя Winsock может может использоваться непосредственно для этого, я бы не рекомендовал его. HTTP - сложный зверь, который нужно реализовать вручную с нуля.

Remy Lebeau 22.06.2018 22:30

Использование Windows HTTP API тоже может быть простым.

procedure TForm1.Button1Click(Sender: TObject);
var http: variant;
begin
 http:=createoleobject('WinHttp.WinHttpRequest.5.1');
 http.open('GET', 'http://lazarus.freepascal.org', false);
 http.send;
 showmessage(http.responsetext);
end;

В приведенном выше коде я подразумеваю, что COM уже был инициализирован для основного потока VCL. Сообщается, что это может быть не всегда так для упрощенных приложений или для приложений LCL. Также это определенно не относится к асинхронной (многопоточной) работе.

Ниже приведен фрагмент реального запущенного кода. Обратите внимание - функционал бонусный. Работать не требуется. Поэтому, пока я отправляю запросы, меня не интересуют их результаты, они игнорируются и сбрасываются.

procedure TfmHaspList.YieldBlinkHTTP(const LED: boolean; const Key_Hardware_ID: cardinal);
var URL: WideString;
begin
  URL := 'http://127.0.0.1:1947/action.html?blink' +
    IfThen( LED, 'on', 'off') + '=' + IntToStr(Key_Hardware_ID);

  TThread.CreateAnonymousThread(
    procedure
    var Request: OleVariant;
    begin
      // COM library initialization for the current thread
      CoInitialize(nil);
      try
        // create the WinHttpRequest object instance
        Request := CreateOleObject('WinHttp.WinHttpRequest.5.1');
        // open HTTP connection with GET method in synchronous mode
        Request.Open('GET', URL, False);
        // set the User-Agent header value
//        Request.SetRequestHeader('User-Agent', 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0');
        // sends the HTTP request to the server, the Send method does not return
        // until WinHTTP completely receives the response (synchronous mode)
        Request.Send;
//        // store the response into the field for synchronization
//        FResponseText := Request.ResponseText;
//        // execute the SynchronizeResult method within the main thread context
//        Synchronize(SynchronizeResult);
      finally
        // release the WinHttpRequest object instance
        Request := Unassigned;
        // uninitialize COM library with all resources
        CoUninitialize;
      end;
    end
  ).Start;
end;

Да, это отличное и простое решение, но не забывайте вызывать CoInitialize(nil); и CoUninitialize в начале и в конце соответственно.

supersan 02.03.2016 11:26

Это упоминается в ссылках для случая асинхронного потока. Однако в этом конкретном примере объект работает в основном потоке VCL, где COM уже был инициализирован. Я полагаю (хотя не проверял) то же самое относится и к LCL в Windows.

Arioch 'The 02.03.2016 11:48

Привет да. Я упомянул об этом, потому что мое приложение выдало мне сообщение «Com not initialized or something error», когда я его использовал (стандартный TForm с кнопкой). Также по какой-то причине, когда я закрыл приложение, оно разбилось после использования методов CoInitialize и CoUninitialize. Просто к вашему сведению.

supersan 02.03.2016 17:04

Была ли ваша переменная "http" локальной? Может быть, вы не уничтожили / не очистили переменную до CoUnInitialize, поэтому она сохранила указатель на COM-объект после выключения COM-подсистемы?

Arioch 'The 02.03.2016 17:20

В моем конкретном случае мне нужно было вызвать в службу localhost, чтобы он не блокировал графический интерфейс, и мне вообще не нужны были какие-либо результаты, даже статус успеха / ошибки. Поэтому я просто продолжал порождать TThread.Anonymous worker, которые инициализировали и закрывали COM внутри себя. Работал как шарм.

Arioch 'The 02.03.2016 17:25

Привет, @supersan. Здесь немного некропостинга. Просто наткнулся на ситуацию в Delphi XE2, когда стандартные диалоги открытия / сохранения просто не работали. В первую очередь функция PromptForFileName, а фактически вся подсистема. Оказалось, что в XE2 функция сохранения / открытия реализована через COM, и эта функция вызывалась в потоке, поэтому об ошибке COM Not Initialized Windows сообщила и проглотила VCL. Однако, поскольку TOpenFileDialog является стандартным компонентом Delphi и работает просто и надежно в основном потоке VCL, это означает, что COM автоматически инициализируется где-то в основном потоке.

Arioch 'The 29.01.2018 12:44

Просто для ссылки на мой предыдущий комментарий: stackoverflow.com/questions/6719853/…

Arioch 'The 31.01.2018 11:38

В более новых версиях Delphi лучше использовать THTTPClient от блока System.Net.HttpClient, так как он стандартный и кроссплатформенный. Простой пример:

function GetURL(const AURL: string): string;
var
  HttpClient: THttpClient;
  HttpResponse: IHttpResponse;
begin
  HttpClient := THTTPClient.Create;
  try
    HttpResponse := HttpClient.Get(AURL);
    Result := HttpResponse.ContentAsString();
  finally
    HttpClient.Free;
  end;
end;

Другие вопросы по теме