Форум программистов, компьютерный форум, киберфорум
Avazart
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
Темы блога относятся к программированию на языке С++

В основном для C++Qt (Qt5.1) и C++ Builder (RAD 2009 и RAD XE3)

Компонент IdHTTP

Запись от Avazart размещена 08.08.2012 в 21:58
Показов 191569 Комментарии 4
Метки c++, c++builder, http, idhtp, indy

Компонент IdHTTP позволяет выполнять GET и POST запросы согласно протоколу HTTP.
( Загружать html- страницы, файлы, производить авторизацию на сайтах )

Содержание

1. Простые примеры. (загрузить страницу сайта, загрузка в файл, заголовки запроса и ответа)
2. Обработка исключений
3. Создание компонета динамически
4. Перенаправление ( редирикт )
5. Кодировки ( cp1251, UTF-8 )
6. Отображения хода загрузки
7. Cookie
8. POST-запрос для авторизации на сайте.
8.1. POST-запрос c загрузкой файла на сайт.(multipart/form-data)
9. Получение страниц в сжатом виде.
10. Передача с использованием HTTPS (расширение протокола HTTP, поддерживающее шифрование.)
11. Ведения лога запросов/ответов

Литература.
Темы.

Нажмите на изображение для увеличения
Название: Компоненты.jpg
Просмотров: 3080
Размер:	35.7 Кб
ID:	1146


1. Простые примеры.

1.1. Загрузить страницу сайта.

Простой пример загрузки html страницы в Memo
C++
1
2
3
4
5
6
//----------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  Memo1->Text= IdHTTP1->Get("https://www.cyberforum.ru");// Код страницы
}
//---------------------------------------------------------------------------
1.2.Загрузка в файл.

Сохранить полученную страницу (а также файл ,изображение итп... с сервера) в файл на диск можно используя TMemoryStream :
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//-----------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  TMemoryStream *MS = new  TMemoryStream;
  try
  {
     IdHTTP1->Get("https://www.cyberforum.ru",MS);
     MS->SaveToFile("1.html");
  }
  __finally
  {
     delete MS;
  }
}
//---------------------------------------------------------------------------
Или через TFileStream :
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//-----------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  TFileStream* FS = new TFileStream("1.html", fmCreate | fmOpenWrite);
  try
  {
     IdHTTP1->Get("https://www.cyberforum.ru", FS);
  }
  __finally
  {
    delete FS;
  }
}
//---------------------------------------------------------------------------
1.3. Заголовки запроса и ответа.

Доступ к полям заголовка запроса можно получить через IdHTTP1->Request-> ...
К примеру имитируем запрос от Firefox
C++
1
2
3
4
5
IdHTTP1->Request->UserAgent= "Mozilla/5.0 (Windows NT 6.1; rv:16.0) Gecko/20100101 Firefox/16.0";
IdHTTP1->Request->Accept= "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
IdHTTP1->Request->AcceptLanguage= "ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3";
IdHTTP1->Request->Connection= "keep-alive";
IdHTTP1->Request->Host= "store.steampowered.com";
Если не заполнять эти поля, то будут отсылаться значения полей по умолчанию Indy

После посылки запроса проверить ответ сервера можно, посмотрев содержимое свойство IdHTTP1->Response-> ....
C++
1
2
3
4
5
6
7
//-----------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 Memo1->Text= IdHTTP1->Get("https://www.cyberforum.ru");// Код страницы
 Memo2->Text= IdHTTP->Response->ResponseText;// Ответ сервера
}
//---------------------------------------------------------------------------
Можно выполнить запрос без загрузки самой страницы (например для проверки её существования)

C++
1
2
3
4
5
6
7
//------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  IdHTTP1->Head("https://www.cyberforum.ru");
  Memo1->Text= IdHTTP1->Response->RawHeaders->GetText();
}
//---------------------------------------------------------------------------------
2. Обработка исключений.

При загрузки страницы могут возникать исключения [7] которые иногда надо обрабатывать
(с целью перенаправления, руссификации и ведения лога ошибок )

Для отлова всех Indy- исключений достаточно :
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//-------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
   // Добавляем обработку исключения
  try
  {
    Memo1->Text= IdHTTP1->Get("https://www.cyberforum.ru");
  }
  catch(const EIdException& E)   // Ловим исключения Indy
  {
    ShowMessage("Ошибка:\n"+E.Message);
  };
}
//---------------------------------------------------------------------------
Если смотреть подробнее стоит выделить:

1. Исключения сокетов [6]
2. Ответы сервера HTTP [2]
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
//----------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  try
  {
    Memo1->Text= IdHTTP1->Get("https://www.cyberforum.ru");
  }
  catch(const EIdSocketError& E)  // Исключения сокетов
  {
    // Обработка, можно получить код ошибки сокета через E.LastError
    // см.  msdn.microsoft.com/en-us/library/windows/desktop/ms740668%28v=vs.85%29.aspx
    ShowMessage("Ошибка:\n"+E.Message);
  }
  catch(const EIdHTTPProtocolException& E)
  {
    // Можно получить код ответа сервера  HTTP  через E.ErrorCode
    switch(E.ErrorCode)
    {
    case 400:
      ShowMessage("400 Cервер обнаружил в запросе клиента синтаксическую ошибку");
      break;
    case 401:
      ShowMessage("401 Запрос требует идентификации пользователя.");
      break;
    case 404:
      ShowMessage("404 Страница не найдена");
      break;
      // ... итд полный список кодов смотри ru.wikipedia.org/wiki/Список_кодов_состояния_HTTP
    default :
      ShowMessage(String(E.ErrorCode)+" "+E.Message);
      break;
    }
  }
  catch(const EIdException& E)// Другие исключения Indy
  {
    ShowMessage("Ошибка:\n"+E.Message);
  }
  catch(const Exception& E)   // Другие НЕ Indy исключения
  {
    ShowMessage("Ошибка:\n"+E.Message);
  }
}
//---------------------------------------------------------------------------
Рассмотрим случай из темы Как проверить наличие соединения с Интернетом\Сетью посты #30,#31.

При коде
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  try
  {
    IdHTTP1->ConnectTimeout = 1000;
    IdHTTP1->ReadTimeout = 1000;
 
    IdHTTP1->Get("https://www.cyberforum.ru");
    MessageBox(0, "Соединение с Интернет есть", "Информация", MB_OK + MB_ICONINFORMATION);
  }
  catch(const EIdHTTPProtocolException& E)
  {
    // ....
  }
  catch(const EIdSocketError& E)
  {
    ShowMessage(E.LastError);
  }
}
//---------------------------------------------------------------------------
Цитата Сообщение от Avazart Посмотреть сообщение
Пробую этот код. Как бы работает.
Но вот в чем проблема компонент создается не динамически и если отключаю интернет - нажимаю кнопку, выбивает что интернета нет(или 11001 или 10054) потом я подключаю интернет и при повторной проверке- опять выбивает туже ошибку говоря что интернета нет ( хотя он есть ).
Я так понял компонет не выходит из "состояния ошибки".
Нажмите на изображение для увеличения
Название: Ошибка сокета #11001.jpg
Просмотров: 2820
Размер:	12.7 Кб
ID:	1117Нажмите на изображение для увеличения
Название: Ошибка сокета #10054.jpg
Просмотров: 2483
Размер:	13.4 Кб
ID:	1116
Цитата Сообщение от MikeSoft Посмотреть сообщение
Вы должны его выводить, сам он практически ничего не сделает.
При получении ReadTimeout соединение останется открытым, поэтому его нужно закрыть.
К тому же, есть Connection Gracefully Closed. Это сообщение говорит о том, что удалённая сторона сама послала команду на закрытие соединение. В этом случае, тоже необходимо закрыть всё вручную. Поэтому, проще прописать закрытие на любое действие. Закрытие в новых версиях - это обычный Disconnect ... а вот в старых версиях Indy необходимо было непосредственно закрывать Socket.
Т.е. после выполнения запроса, соединение может оставаться открытым, поэтому если соединение с данным сайтом больше не нужно, то необходимо позаботиться о его закрытии, в том числе в случаях выбрасывания исключения
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  try
  {
    try
    {
      IdHTTP1->Head("https://www.cyberforum.ru");
      Memo1->Text= IdHTTP1->Response->RawHeaders->GetText();
    }
    __finally
    {
      IdHTTP1->Disconnect();
      /*  Независимо от того что произошло закрываем соединение.
         (не важно было ли исключение или нет, не важно какой тип исключения) */
    }
  }
  catch(const EIdException& E)   // Ловим исключения Indy
  {
    ShowMessage("Ошибка:\n"+E.Message);
  }
  // catch(  )  тут может обрабатваться другие типы ошибок ...
}
//---------------------------------------------------------------------------
Есть так же другой вариант решения этой проблемы - создавать компонент динамически, в таком случае закрытие будет происходить при уничтожении компонента.

3. Создание компонета динамически.

Если предпологается загружать страницы например в потоке, то удобно создавать компонент динамически.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//-------------------------------------------------------------------
/* заголовки необходимые для динамического создания
(обычно автоматом прописываются в h-файл формы
при кидании компонента на форму )*/
#include <IdBaseComponent.hpp>
#include <IdComponent.hpp>
#include <IdHTTP.hpp>
#include <IdTCPClient.hpp>
#include <IdTCPConnection.hpp>
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  // Динамическое создание
  TIdHTTP* IdHTTP2= new TIdHTTP(NULL) ;
  try
  {
    Memo1->Text= IdHTTP2->Get("https://www.cyberforum.ru");
  }
  catch(const EIdException &E)  // Если не обрабатывать исключения удаление IdHTTP2 не произойдет
  {
    ShowMessage("Ошибка:\n"+E.Message);
  }
  delete IdHTTP2; 
}
//---------------------------------------------------------------------------
При использовании std::auto_ptr<> отпадает необходимость заботиться об освобождении памяти.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//---------------------------------------------------------------------
#include <memory>    //std::auto_ptr<>
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
// Динамическое создание с помощью  auto_ptr
  std::auto_ptr<TIdHTTP> IdHTTP2 (new TIdHTTP(NULL) );
  try
  {
    Memo1->Text= IdHTTP2->Get("https://www.cyberforum.ru");
  }
  catch(const EIdException& E)   // Ловим исключения Indy
  {
    ShowMessage("Ошибка:\n"+E.Message);
  };
}
//---------------------------------------------------------------------------
4. Перенаправление ( редирикт ).

Для автоматического перехода на перенаправляемую страницу необходимо установить свойство
C++
1
IdHTTP1->HandleRedirects= true;
Иначе будет генерироватся исключения с кодом 301,302 идр.. [2]

Название: Исключение при перенаправлении с кодом 302.jpg
Просмотров: 53317

Размер: 12.9 Кб

Судя по статье [1] IdHTTP1->HandleRedirects=true; не всегда помогает при перенаправлении, поэтому возникает необходимость обрабатывать перенаправление вручную.

С помощью IdHTTP1->Response->Location можно получить url куда нас собственно перенаправляют.
ErrorCode - код состояния (ответа) HTTP сервера[2]
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//---------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  try
  {
    Memo1->Text= IdHTTP1->Get("https://www.cyberforum.ru");
    // Тут может быть другой код ...
  }
  catch(const EIdHTTPProtocolException &E)
  {
    if( E.ErrorCode == 302 ) // код состояния HTTP- cервера [2]
    {
      Memo1->Text= IdHTTP1->Get(IdHTTP1->Response->Location); // переход
    }
  }
  catch(const EIdException &E)// Другие исключения Indy
  {
    ShowMessage("Ошибка:\n"+E.Message);
  }
  catch(const Exception &E)   // Другие НЕ Indy исключения
  {
    ShowMessage("Ошибка:\n"+E.Message);
  }
}
//---------------------------------------------------------------------------
5. Кодировки.
Иногда стоит задача получить ответ сервера в определенной кодировке, для этого необходимо использовать TStringStream c указанием нужной кодировки в его конструкторе.

C++
1
2
3
4
5
6
7
8
9
10
11
12
#include <memory>
//---------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  std::auto_ptr<TStringStream>    // для UTF8
  ContentStream(new TStringStream("",TEncoding::UTF8,true));
//std::auto_ptr<TStringStream> // для Windows cp1251
// ContentStream(new TStringStream("",TEncoding::GetEncoding(1251),true));
  IdHTTP1->Get("http://avazart.zz.mu",ContentStream.get() );
  Memo1->Text= ContentStream->DataString;
}
//--------------------------------------------------------------------
Старый подход к решению проблемы кодировок.
5.1. При загрузки страниц с кодировкой cp1251 русcкие символы отображаются не верно, я предпологаю что это связано с недоработкой Indy в плане совместимости с Юникодом.Поэтому приходится использовать самописные ф-ции вроде этой:
( Тема: Инди и русские символы )
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//-----------------------------------------------------------------------
String WinToUnicode(const String St)
{
  String Result="";
  for (int i = 1; i <= St.Length(); i++)
  {
    if (int(St[i])>= 0x00C0 && int(St[i])<= 0x00FF)
      Result += wchar_t(int(St[i])+0x350);
    else Result += St[i];
  }
  return Result;
}
//------------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  Memo1->Text= WinToUnicode( IdHTTP1->Get("http://my.mail.ru/cgi-bin/login?") );
}
//---------------------------------------------------------------------------
5.2. Для отображения UTF-8 можно использовать такую ф-цию
( Тема: Русские символы и html )
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
//-----------------------------------------------------------------------
wchar_t * utf8_to_unicode(char *utf8_string)
{
  int err;
  wchar_t * res;
  int res_len = MultiByteToWideChar(
                  CP_UTF8,            // Code page
                  0,                  // No flags
                  utf8_string,        // Multibyte characters string
                  -1,                 // The string is NULL terminated
                  NULL,               // No buffer yet, allocate it later
                  0                   // No buffer
                );
  if (res_len == 0)
  {
    return NULL;
  }
  res = (wchar_t*)calloc(sizeof(wchar_t), res_len);
  if (res == NULL)
  {
    return NULL;
  }
  err = MultiByteToWideChar(
          CP_UTF8,            // Code page
          0,                  // No flags
          utf8_string,        // Multibyte characters string
          -1,                 // The string is NULL terminated
          res,                // Output buffer
          res_len             // buffer size
        );
  if (err == 0)
  {
    free(res);
    return NULL;
  }
  return res;
}//------------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  Memo1->Text=
    utf8_to_unicode(AnsiString( IdHTTP1->Get("http://my.mail.ru/cgi-bin/login?") ).c_str() );
}
//---------------------------------------------------------------------------

6. Отображения хода загрузки.

Для отображения используем компонент TProgressBar.
Вписываем код в соответствующие обработчики событий IdHTTP.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  Memo1->Text= IdHTTP1->Get("https://www.cyberforum.ru");// Код страницы
}
//---------------------------------------------------------------------------
void __fastcall TForm1::IdHTTP1WorkBegin(TObject *ASender, TWorkMode AWorkMode, __int64 AWorkCountMax)
 
{
// Устанавливаем размер загружаемых данных
  if(AWorkMode==TWorkMode::wmRead)
    ProgressBar1->Max = AWorkCountMax;  // download
  else if(AWorkMode==TWorkMode::wmWrite)
    ProgressBar2->Max = AWorkCountMax; // upload
}
//---------------------------------------------------------------------------
void __fastcall TForm1::IdHTTP1Work(TObject *ASender, TWorkMode AWorkMode, __int64 AWorkCount)
 
{
  // Ход загрузки
  if(AWorkMode==TWorkMode::wmRead)
    ProgressBar1->Position = AWorkCount;  // download
  else if(AWorkMode==TWorkMode::wmWrite)
    ProgressBar2->Position = AWorkCount;  //  upload
}
//---------------------------------------------------------------------------
void __fastcall TForm1::IdHTTP1WorkEnd(TObject *ASender, TWorkMode AWorkMode)
{
// Конец загрузки тут можно обнулить прогресс бары (а можно этого и не делать)
//    if(AWorkMode==TWorkMode::wmRead)
//        ProgressBar1->Position = 0;
//   else if(AWorkMode==TWorkMode::wmWrite)
//        ProgressBar2->Position = 0;
} 
//---------------------------------------------------------------------------
7. Cookie

Для работы с Cookie можно использовать компонент TIdCookieManager связав его с TIdHTTP
C++
1
2
IdHTTP1->CookieManager= IdCookieManager1;
IdHTTP1->AllowCookies= true;
Стоит заметить что на некоторых сайтах IdCookieManager1 не может воспринять куки так как они записаны в особой форме, поэтому приходится устанавливать куки вручную. (Тема: https://www.cyberforum.ru/post235829.html )

8. POST-запрос для авторизации на сайте. [8]
( Тема: Бот на С++ )

Для авторизации на сайте нужно знать как должен выглядит POST-запрос.
В POST-запросе побычно передаются таки данные как логин,пароль итп.
Определить форму запроса можно просмотрев что шлет браузер при авторизации.
В FireFox для этого можно использовать специальный плагин для просмотров HTTP заголовков.
Также можно использовать такие сниферы как HttpAnalyzerV5 или Charles

Итак пример запроса котрый шлет браузер для авторизации :

Нажмите на изображение для увеличения
Название: Post.jpg
Просмотров: 3426
Размер:	195.2 Кб
ID:	1271

http://ganjafarm.ru/?nick=player2012&password=test&page=login

Разбираем этот запрос по строкам согласно разделителям "?" и "&" , запрос передается в виде "переменная = значение"

http://ganjafarm.ru/
? nick=player2012
& password=test
& page=login

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  TStringList *SL= new TStringList;
 
  IdHTTP1->CookieManager= IdCookieManager1;
  IdHTTP1->AllowCookies= true;
 
  String Url = "http://ganjafarm.ru";
  SL->Add("nick=player2012");   // ? nick=player2012
  SL->Add("password=test");     // & password=test
  SL->Add("page=login");          // & page=login
 
  try
  {
    Memo1->Text= IdHTTP1->Post(Url,SL);
  }
  catch(const EIdException &E)   // Ловим исключения Indy
  {
    ShowMessage("Ошибка:\n"+E.Message);
  };
 
  delete SL;
}
//---------------------------------------------------------------------------
Что бы после авторизации сохранялись кукисы нужно связывать IdHTTP с TIdCookieManager как говорилось выше.

8.1. POST-запрос c загрузкой файла на сайт.

Для запроса содержащего multipart/form-data предназначен класс TIdMultiPartFormDataStream объект которого передается как второй параметр в метод Post()

В качестве примера приведу код загрузки файла на файлообменник
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/* Далее "ввв" вместо "www", почему ? - спросите у АДминов */
// [url]http://ввв.***********[/url] - файлообменник с предпросмотром изображения  
//---------------------------------------------------------------------------
#include <memory>       // for std::auto_ptr<>
#include <StrUtils.hpp> // for PosEx()
//---------------------------------------------------------------------------
String ParseLink(String Text,int start,String LeftTag,String RightTag)
{
  int left = PosEx(LeftTag,Text,start) + LeftTag.Length();
  int right = PosEx(RightTag,Text,left);
 
  if(left< LeftTag.Length() || right<left) return "";
 
  return Text.SubString(left,right-left);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  if(OpenPictureDialog1->Execute() )
  {
    std::auto_ptr<TIdMultiPartFormDataStream>
    PostData(new TIdMultiPartFormDataStream);
 
    PostData->AddFormField("upload","yes",""); // Один из необходимых полей для данного файлообменника
 
    String Name= "F";                  // Имя поля соответствующего файлу
    String FileName= OpenPictureDialog1->FileName;  // Путь к файлу
 
    PostData->AddFile(Name,FileName);
 
    String Url= "http:/ввв.***********/action.aspx";
 
    String Content = IdHTTP1->Post(Url, PostData.get());
 
    // Вытаскиваем ссылку на изображение
    String Link= ParseLink(Content,1,"[img]","[/img]");
    // Выводим  ссылку
    LinkLabel1->Caption= "<a href=""+Link+"">"+Link+"</a>";
  }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::LinkLabel1LinkClick(TObject *Sender, const UnicodeString Link,
    TSysLinkType LinkType)
{
  // Перейти по ссылке в браузере
  ShellExecuteW(Handle,L"open",Link.w_str(),NULL,NULL,SW_RESTORE);
}
//---------------------------------------------------------------------------
Метод AddFormField() добавляет поле с указанным именем и его значением, а метод AddFile() добавляет файл.

В указанных методах также можно дополнительными параметрами явно указывать тип контента (ContentType) и Сharset.

Из справки XE3:
C++
1
public: __fastcall TIdFormDataField AddFormField(const AnsiString AFieldName, const AnsiString AFieldValue, const AnsiString ACharset = "", const AnsiString AContentType = "", const AnsiString AFileName = "");
Из справки Indy
Delphi
1
2
3
4
5
procedure AddFile(
    const AFieldName: string; 
    const AFileName: string; 
    const AContentType: string
);
Примечание: после отправки POST- запроса с multipart/form-data поле заголовка Content Type изменится на:
Code
1
multipart/form-data; boundary= -- ...
Поэтому для отправки в дальнейшем "обычного" POST запроса нужно Content Type предварительно восстановить:
C++
1
IdHTTP1->Request->ContentType= "application/x-www-form-urlencoded";
(Тема: Загрузка файла на сервер и последующая публикация )



9. Получение страниц в сжатом виде.
( Тема: Декомпрессия принятой страницы )

Некоторые сервера поддерживают передачу страниц в сжатом виде, это увеличивает скорость загрузки страницы.

Для получения страницы в сжатом виде устанавливаем свойство:
C++
1
IdHTTP1->Request->AcceptEncoding = "gzip" ;
Для декомпрессиии используем компонент TIdCompressorZLib ( Не работает в RAD XE2, но работает в RAD XE3 )

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//------------------------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  IdHTTP1->HandleRedirects= true;
  IdHTTP1->Request->AcceptEncoding = "gzip";
  IdHTTP1->Compressor =  IdCompressorZLib1;
 
  try
  {
    Memo1->Text= IdHTTP1->Get("http://google.ru")  ; // google позволяет получать в сжатом виде
  }
  catch(const EIdException &E)   // Ловим исключения Indy
  {
    ShowMessage("Ошибка:\n"+E.Message);
  };
}
//---------------------------------------------------------------------------
10. Передача с использованием HTTPS.
( Тема: Indy и HTTPS )

Для работы с протоколом https связываем TIdHTTP c компонентом TIdSSLIOHandlerSocketOpenSSL
Скорее всего понадобиться библиотеки libeay32.dll и ssleay32.dll которые можно скачать например здесь: http://indy.fulgan.com/SSL/ их необходимо положить в папку с exe-ником вашей программы

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//-------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  IdHTTP1->IOHandler = IdSSLIOHandlerSocketOpenSSL1;
  try
  {
    Memo1->Text= IdHTTP1->Get("https://my.webmoney.ru");
  }
  catch(const EIdException &E)// Ловим исключения Indy
  {
    ShowMessage("Ошибка:\n"+E.Message);
  };
}
//------------------------------------------------------
11. Ведения лога запросов/ответов

"Глубины Indy" Перевод: А.П. Подгорецкий стр 71
13.2. Ведение логов (Logging)

Indy 8.0 имел один компонент ведения логов, который мог быть использован для различных
источников. В Indy 9.0 компоненты логов теперь базируются на новом общем классе и имеют
специализированные классы. Базовый класс также предоставляет свойства и функциональность,
такую как регистрация времени, в дополнение к данным.
Все классы ведения логов реализованы, как перехватчики. Это означает, что они перехватывают
входящие данные, после того, как они были прочитаны и перед передачей исходящих в
источник.

Специализированные классы логов, следующее:
TIdLogEvent – возбуждает события, когда данные приняты, или переданы, или при
появлении события состояния. Класс TIdLogEvent полезен для реализации
пользовательских логов, без необходимости в реализации нового класса.
TIdLogFile – Записывает данные в файл.
TIdLogDebug – Записывает данные в окно отладки Windows или в консоль Linux. Также
отмечает данные, как принятые данные, переданные данные или информация о статусе.
Класс TidLogDebug полезен для проведения простой отладки.
TIdLogStream – Не добавляет комментариев, отметок к данным, как другие классы.
Вместо этого просто записывает сырые данные в указанный поток. Класс TIdLogStream
может использоваться по разному, но обычно он очень эффективно используется для QA
тестирования и удаленной отладки. Могут быть построены и пользовательские классы
логов.
И так рассмотрим пример с использованием TIdLogEvent для ведения лога в Memo1.

Добавляем компонент на форму, создаем соответствующие для него обработчики событий

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
// Это можно сделать визуально через инспектор обьектов
  IdLogEvent1->ReplaceCRLF = false; // чтоб не проводилась замена символов перевода строк
  IdLogEvent1->Active=true;
 
  IdHTTP1->Intercept = IdLogEvent1; // Связываем  IdHTTP1 с  IdLogEvent1
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  String Content;
  try
  {
    Content = IdHTTP1->Get("https://www.cyberforum.ru");
  }
  catch(EIdException &E)   // Ловим исключения Indy
  {
    ShowMessage("Ошибка:\n"+E.Message);
  }
  if(IdHTTP1->Connected() )
    IdHTTP1->Disconnect();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::IdLogEvent1Sent(TComponent *ASender,
                                        const UnicodeString AText,
                                        const UnicodeString AData)
{
  Memo1->Lines->Add(AData); // Передача
}
//---------------------------------------------------------------------------
void __fastcall TForm1::IdLogEvent1Received(TComponent *ASender,
    const UnicodeString AText,
    const UnicodeString AData)
{
  Memo1->Lines->Add( AData );  // Приём
}
//---------------------------------------------------------------------------
void __fastcall TForm1::IdLogEvent1Status(TComponent *ASender,
    const UnicodeString AText)
 
{
  Memo1->Lines->Add(AText); //  Статус соединения
}
//---------------------------------------------------------------------------
В место компонентов Indy для лога, иногда удобнее использовать самописную ф-цию вроде этой:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void __fastcall AddToLog(TStrings* Lines, TIdHTTP* IdHTTP, String HtmlContent="Контент не указан")
{
    Lines->Add("------------- Запрос --------------------");
    Lines->Add( IdHTTP->Request->URL);
    Lines->AddStrings( IdHTTP->Request->RawHeaders);
    Lines->Add("");
 
    Lines->Add("------------- Ответ --------------------");
    Lines->Add( IdHTTP->ResponseText);
    Lines->AddStrings( IdHTTP->Response->RawHeaders);
    Lines->Add("");
 
    Lines->Add("------------- Контент --------------------");
    Lines->Add(HtmlContent);
    Lines->Add("");
}

Литература:

1. Для начинающих работать с компонентом idHTTP в Delphi

2. http://ru.wikipedia.org/wiki/%... D1%8F_HTTP

3. Пример авторизации на сайте с помощью idHTTP.Post

4. Компоненты Internet Direct (Indy). Вводная статья для новичков

5. Уроки C++ Builder с нуля

6. http://msdn.microsoft.com/en-u... s.85).aspx

7. http://docwiki.embarcadero.com... lException

8. http://parsing-and-i.blogspot.... ppost.html

9. "Глубины Indy" Перевод: А.П. Подгорецкий

Темы:

1. Сайт в мемо
2. Инди и русские символы
3. Авторизация на сайте через IdHTTP
4. Чтение html из url
5. Создание и копирование настроек IdHTTP
6. Post Запрос авторизации на сайте + куки
7. Как проверить наличие соединения с Интернетом\Сетью
8. IdHTTP авторизаця на форуме
9. Парсинг характеристик товара с Яндекс.Маркета
10. Взять значения из сайта
11. Поток: программа зависает во время парсинга
12. Наличие файла на сайте
13. Русские символы и html
14. IdHTTP Авторизация на сайте
15. Кодировка страницы
16. IdHTTP Русский запрос!
17. IdHTTP или TIdMultiPartFormDataStream передает кириллицу в неправильной кодировке
18. idHTTP и unicodeString
19. Очень медленно скачивает страницу (TIdHTTP). Как ускорить? // TIdCompressorZLib,сжатые страницы
20. Indy и HTTPS // IdSSLIOHandlerSocketOpenSSL
21. Скачка файла с интернета // Прогрессбар
22. Пример авторизации на mail.ru (С++)
23. Как отправить запрос на онлайн-сервис // TIdMultiPartFormDataStream
24. Бот на С++ // Post запрос
25. IdHTTP->Get в потоке и прогрессом
26. Получение результата после POST запроса
27. IdHTTP Русский запрос!
28. Загрузка файла на сервер и последующая публикация
29. Нормализация URL в C++ Builder
30. TIdFormDataField передача XML
31. Как сохранять и загружать cookie? [C++/Indy]
Метки c++, c++builder, http, idhtp, indy
Размещено в C++, C++Builder
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 4
Комментарии
  1. Старый комментарий
    Аватар для Dinkin
    Возможно ли посылать файл на сервер не брав его из директории, а сразу из стрим?
    Запись от Dinkin размещена 08.04.2015 в 14:32 Dinkin вне форума
  2. Старый комментарий
    Аватар для Avazart
    Как я помню можно, через TMemoryStream или через TStringStream.

    Я уже не помню точно как это делал, но кажется у TIdFormDataField есть свойство FieldStream.
    Запись от Avazart размещена 09.04.2015 в 20:49 Avazart вне форума
  3. Старый комментарий
    Аватар для Почтальон
    Огромнейшее спасибо за предоставленную информацию, никакой воды, все по делу!
    Запись от Почтальон размещена 03.06.2015 в 21:25 Почтальон вне форума
  4. Старый комментарий
    Цитата Сообщение от Dinkin
    Возможно ли посылать файл на сервер не брав его из директории, а сразу из стрим?
    C++
    1
    2
    3
    4
    
    std::auto_ptr<TIdMultiPartFormDataStream> PostData(new TIdMultiPartFormDataStream);
    TFileStream *fs = new TFileStream(file_path, fmOpenRead | fmShareDenyNone);
    PostData->AddFormField("file","","",fs,file_path);
    IndyVT->Post(Url, PostData.get());
    Как то так.
    Запись от Dr.Xank размещена 28.03.2017 в 22:41 Dr.Xank вне форума
 
Новые блоги и статьи
Мобильное приложение ColorStep
pavlinmavlin 17.09.2026
Реализовал приложение Красный, Зеленый, Синий в Unity3d + c#. Название изменил на ColorStep. Приложение прошло модерацию и теперь доступно для скачивания. Делал его сам, шаг за шагом — и вот,. . .
Запрет дублирования строк в табличной части
Maks 13.09.2026
Реализация из решения ниже выполнена на нетиповом справочнике "Нормы ТО" с табличной часть "Виды ТО", разработанного в КА2, со следующими реквизитами: - ВидТО (СправочникСсылка. ВидыТО); - ВидГСМ. . .
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр.
Jin X 06.09.2026
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр. Работая с форумом и нейросетями в браузере часто хочется что-то подкорректировать или добавить какого-то функционала. Ниже прикреплён. . .
Программа опроса у.з. расходомера SLS-720F
Argus19 02.09.2026
Программа опроса у. з. расходомера SLS-720F Программа опрашивает один раз в минуту три ультразвуковых расходомера SLS-720F через интерфейс RS-485 по протоколу Modbus RTU. Опрашиваются регистры. . .
Hyper-V: Компьютер должен поддерживать доверенный платформенный модуль 2.0.
Maks 31.08.2026
При установке Windows 11 на виртуальную машину Hyper-V 2-го поколения вылезла такая ошибка: Решение: в параметрах виртуальной машины, в разделе "Безопасность" (Security) активировать флаг. . .
Архитектура биовида Стива в Майнкрафте: Зачем бонобо кубический каннибализм
anaschu 30.08.2026
Кубический Вагинокапитализм в Minecraft: Математический инвариант ОДУ и рок Стивов-бонобо Главная задача разработанной «Модели Всего» — наглядно продемонстрировать наличие системной «судьбы». . .
Оттачиваю умение писать js программы.
russiannick 30.08.2026
Проектом выходного дня стало написание Книги шифров Виженера. Итогом стала версия 200, синий туман. Синий туман назван так, потому что замораживает текст под собой. Нажатие синих кнопок управляют. . .
мат медиц модель 30. презентация проекта
anaschu 27.08.2026
хоп хоп хоп хидахоп, а я кладую))
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru