Поделиться через


Общие сведения о сеансах WinHTTP

Службы HTTP Microsoft Windows (WinHTTP) предоставляют набор функций C/C++, которые позволяют приложению получать доступ к ресурсам HTTP в Интернете. В этом разделе представлен обзор использования этих функций для взаимодействия с HTTP-сервером.

Использование API WinHTTP для доступа к Интернету

На следующей схеме показан порядок, в котором обычно вызываются функции WinHTTP при взаимодействии с HTTP-сервером. Затеняемые поля представляют функции, создающие дескриптор HINTERNET , а обычные — функции, использующие эти дескрипторы.

функции, создающие дескрипторы

Инициализация WinHTTP

Перед взаимодействием с сервером необходимо инициализировать WinHTTP, вызвав WinHttpOpen. WinHttpOpen создает контекст сеанса для хранения сведений о сеансе HTTP и возвращает дескриптор сеанса. С помощью этого дескриптора функция WinHttpConnect может указать целевой сервер HTTP или HTTPS.

Примечание

Вызов WinHttpConnect не приводит к фактическому подключению к HTTP-серверу, пока не будет выполнен запрос для определенного ресурса.

 

Открытие запроса

Функция WinHttpOpenRequest открывает HTTP-запрос для определенного ресурса и возвращает дескриптор HINTERNET , который может использоваться другими функциями HTTP. WinHttpOpenRequest не отправляет запрос на сервер при вызове. Функция WinHttpSendRequest фактически устанавливает подключение по сети и отправляет запрос.

В следующем примере показан пример вызова WinHttpOpenRequest , использующий параметры по умолчанию.

HINTERNET hRequest = WinHttpOpenRequest( hConnect, L"GET", NULL, NULL, NULL, NULL, 0);

Добавление заголовков запросов

Функция WinHttpAddRequestHeaders позволяет приложению добавлять дополнительные заголовки запросов в свободном формате в дескриптор HTTP-запроса. Он предназначен для использования сложными приложениями, которым требуется точный контроль над запросами, отправляемыми на HTTP-сервер.

Для функции WinHttpAddRequestHeaders требуется дескриптор HTTP-запроса, созданный WinHttpOpenRequest, строка, содержащая заголовки, длину заголовков и любые модификаторы.

С WinHttpAddRequestHeaders можно использовать следующие модификаторы.

Модификатор Описание
WINHTTP_ADDREQ_FLAG_ADD Добавляет заголовок , если он не существует. Используется с WINHTTP_ADDREQ_FLAG_REPLACE.
WINHTTP_ADDREQ_FLAG_ADD_IF_NEW Добавляет заголовок только в том случае, если он еще не существует; В противном случае возвращается ошибка.
WINHTTP_ADDREQ_FLAG_COALESCE Объединяет заголовки с тем же именем.
WINHTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA Объединяет заголовки с тем же именем с помощью запятой. Например, при добавлении "Accept: text/*" и "Accept: audio/*" с этим флагом формируется один заголовок "Accept: text/*, audio/*", что приводит к слиянию первого заголовка. Вызывающее приложение может обеспечить согласованность схемы в отношении объединенных или отдельных заголовков.
WINHTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON Объединяет заголовки с тем же именем с помощью точки с запятой.
WINHTTP_ADDREQ_FLAG_REPLACE Заменяет или удаляет заголовок. Если значение заголовка пустое и заголовок найден, оно удаляется. Если значение заголовка не является пустым, значение заголовка заменяется.

 

Отправка запроса

Функция WinHttpSendRequest устанавливает соединение с сервером и отправляет запрос на указанный сайт. Для этой функции требуется дескриптор HINTERNET , созданный WinHttpOpenRequest. WinHttpSendRequest также может отправлять дополнительные заголовки или дополнительные сведения. Необязательные сведения обычно используются для операций, которые записывают сведения на сервер, например PUT и POST.

После того как функция WinHttpSendRequest отправляет запрос, приложение может использовать функции WinHttpReadData и WinHttpQueryDataAvailable на дескрипторе HINTERNET для скачивания ресурсов сервера.

Публикация данных на сервере

Для отправки данных на сервер HTTP-команда в вызове WinHttpOpenRequest должна иметь значение POST или PUT. При вызове WinHttpSendRequestпараметру dwTotalLength следует задать размер данных в байтах. Затем используйте WinHttpWriteData для отправки данных на сервер.

Кроме того, задайте для параметра lpOptionalwinHttpSendRequest адрес буфера, содержащего данные для отправки на сервер. При использовании этого метода необходимо задать для параметров dwOptionalLength и dwTotalLengthwinHttpSendRequest размер публикуемых данных. Вызов WinHttpSendRequest таким образом устраняет необходимость вызова WinHttpWriteData.

Получение сведений о запросе

Функция WinHttpQueryHeaders позволяет приложению получать сведения о HTTP-запросе. Для функции требуется дескриптор HINTERNET , созданный WinHttpOpenRequest, значение уровня информации и длина буфера. WinHttpQueryHeaders также принимает буфер, в котором хранятся сведения, и отсчитываемый от нуля индекс заголовков, перечисляющий несколько заголовков с одинаковым именем.

Используйте любое из значений уровня информации, найденных на странице Флаги сведений о запросе , с модификатором , чтобы управлять форматом, в котором информация хранится в параметре lpvBufferwinHttpQueryHeaders.

Скачивание ресурсов из Интернета

После открытия запроса с помощью функции WinHttpOpenRequest , его отправки на сервер с помощью WinHttpSendRequest и подготовки дескриптора запроса к получению ответа с помощью WinHttpReceiveResponse приложение может использовать функции WinHttpReadData и WinHttpQueryDataAvailable для скачивания ресурса с HTTP-сервера.

В следующем примере кода показано, как скачать ресурс с безопасной семантикой транзакций. В примере кода инициализируется программный интерфейс приложения (API) WinHTTP, выбирается целевой HTTPS-сервер, а затем открывается и отправляется запрос на этот безопасный ресурс. WinHttpQueryDataAvailable используется с дескриптором запроса, чтобы определить объем данных, доступных для скачивания, а затем WinHttpReadData используется для чтения данных. Этот процесс повторяется до тех пор, пока не будет извлечен и отображен весь документ.

  DWORD dwSize = 0;
  DWORD dwDownloaded = 0;
  LPSTR pszOutBuffer;
  BOOL  bResults = FALSE;
  HINTERNET  hSession = NULL, 
             hConnect = NULL,
             hRequest = NULL;

  // Use WinHttpOpen to obtain a session handle.
  hSession = WinHttpOpen( L"WinHTTP Example/1.0",  
                          WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
                          WINHTTP_NO_PROXY_NAME, 
                          WINHTTP_NO_PROXY_BYPASS, 0 );

  // Specify an HTTP server.
  if( hSession )
    hConnect = WinHttpConnect( hSession, L"www.microsoft.com",
                               INTERNET_DEFAULT_HTTPS_PORT, 0 );

  // Create an HTTP request handle.
  if( hConnect )
    hRequest = WinHttpOpenRequest( hConnect, L"GET", NULL,
                                   NULL, WINHTTP_NO_REFERER, 
                                   WINHTTP_DEFAULT_ACCEPT_TYPES, 
                                   WINHTTP_FLAG_SECURE );

  // Send a request.
  if( hRequest )
    bResults = WinHttpSendRequest( hRequest,
                                   WINHTTP_NO_ADDITIONAL_HEADERS, 0,
                                   WINHTTP_NO_REQUEST_DATA, 0, 
                                   0, 0 );


  // End the request.
  if( bResults )
    bResults = WinHttpReceiveResponse( hRequest, NULL );

  // Keep checking for data until there is nothing left.
  if( bResults )
  {
    do 
    {
      // Check for available data.
      dwSize = 0;
      if( !WinHttpQueryDataAvailable( hRequest, &dwSize ) )
        printf( "Error %u in WinHttpQueryDataAvailable.\n",
                GetLastError( ) );

      // Allocate space for the buffer.
      pszOutBuffer = new char[dwSize+1];
      if( !pszOutBuffer )
      {
        printf( "Out of memory\n" );
        dwSize=0;
      }
      else
      {
        // Read the data.
        ZeroMemory( pszOutBuffer, dwSize+1 );

        if( !WinHttpReadData( hRequest, (LPVOID)pszOutBuffer, 
                              dwSize, &dwDownloaded ) )
          printf( "Error %u in WinHttpReadData.\n", GetLastError( ) );
        else
          printf( "%s", pszOutBuffer );

        // Free the memory allocated to the buffer.
        delete [] pszOutBuffer;
      }
    } while( dwSize > 0 );
  }


  // Report any errors.
  if( !bResults )
    printf( "Error %d has occurred.\n", GetLastError( ) );

  // Close any open handles.
  if( hRequest ) WinHttpCloseHandle( hRequest );
  if( hConnect ) WinHttpCloseHandle( hConnect );
  if( hSession ) WinHttpCloseHandle( hSession );