Форум программистов, компьютерный форум, киберфорум
Наши страницы

Компонент IdHTTP

Войти
Регистрация
Восстановить пароль
Темы блога относятся к программированию на языке С++

В основном для C++Qt (Qt5.1) и C++ Builder (RAD 2009 и RAD XE3)
Рейтинг: 4.50. Голосов: 10.

Компонент IdHTTP

Запись от Avazart размещена 08.08.2012 в 21:58
Обновил(-а) Avazart 28.03.2018 в 16:15
Метки 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
Просмотров: 496
Размер:	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("http://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("http://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("http://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("http://www.cyberforum.ru");// Код страницы
 Memo2->Text= IdHTTP->Response->ResponseText;// Ответ сервера
}
//---------------------------------------------------------------------------
Можно выполнить запрос без загрузки самой страницы (например для проверки её существования)

C++
1
2
3
4
5
6
7
//------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  IdHTTP1->Head("http://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("http://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("http://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("http://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
Просмотров: 428
Размер:	12.7 Кб
ID:	1117Нажмите на изображение для увеличения
Название: Ошибка сокета #10054.jpg
Просмотров: 441
Размер:	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("http://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("http://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("http://www.cyberforum.ru");
  }
  catch(const EIdException& E)   // Ловим исключения Indy
  {
    ShowMessage("Ошибка:\n"+E.Message);
  };
}
//---------------------------------------------------------------------------
4. Перенаправление ( редирикт ).

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

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

Размер: 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("http://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("http://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 не может воспринять куки так как они записаны в особой форме, поэтому приходится устанавливать куки вручную. (Тема: Авторизация на сайте )

8. POST-запрос для авторизации на сайте. [8]
( Тема: www.cyberforum.ru/cpp-beginners/thread639249.html )

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

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

Нажмите на изображение для увеличения
Название: Post.jpg
Просмотров: 1356
Размер:	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 изменится на:
Код:
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("http://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/%D0%A1%...%B8%D1%8F_HTTP

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

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

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

6. http://msdn.microsoft.com/en-us/libr...(v=vs.85).aspx

7. http://docwiki.embarcadero.com/Libra...tocolException

8. http://parsing-and-i.blogspot.com/2009/05/idhttppost.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
Просмотров 40330 Комментарии 4
Всего комментариев 4

Комментарии

  1. Старый комментарий
    Аватар для Dinkin
    Возможно ли посылать файл на сервер не брав его из директории, а сразу из стрим?
    Запись от Dinkin размещена 08.04.2015 в 14:32 Dinkin вне форума
    Обновил(-а) Dinkin 08.04.2015 в 16:13
  2. Старый комментарий
    Аватар для Avazart
    Как я помню можно, через TMemoryStream или через TStringStream.

    Я уже не помню точно как это делал, но кажется у TIdFormDataField есть свойство FieldStream.
    Запись от Avazart размещена 09.04.2015 в 20:49 Avazart на форуме
    Обновил(-а) Avazart 09.04.2015 в 20:52
  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 вне форума
 
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru