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


Перенос приложений WinINet в WinHTTP

Службы HTTP Microsoft Windows (WinHTTP) предназначены для средних и внутренних серверных приложений, требующих доступа к стеку клиентов HTTP. Microsoft Windows Internet (WinINet) предоставляет стек http-клиентов для клиентских приложений, а также доступ к протоколам FTP, SOCKSv4 и Gopher. Этот обзор поможет определить, будет ли перенос приложений WinINet в WinHTTP полезным. В нем также описываются конкретные требования к преобразованию.

Вещи, которые следует учесть перед переносом вашего приложения WinINet

Рассмотрите возможность переноса приложения WinINet в WinHTTP, если ваше приложение будет использовать:

  • Стек клиента HTTP, безопасный для сервера.
  • Минимальное использование стека.
  • Масштабируемость серверного приложения.
  • Меньше зависимостей от API, связанных с платформой.
  • Поддержка имперсонации потока.
  • HTTP-стек, удобный для эксплуатации.
  • Доступ к скриптируемому объекту WinHttpRequest.

Не рекомендуется переносить приложение WinINet в WinHTTP, если оно должно поддерживать одно или несколько следующих компонентов:

  • Протокол FTP или Gopher из стека HTTP.
  • Поддержка протокола SOCKSv4 для взаимодействия с прокси-серверами SOCKS.
  • Автоматические службы модемного соединения.

Если вы решите перенести приложение в WinHTTP, в следующих разделах описано, как выполнить преобразование.

Для примера приложения для WinINet и WinHTTP сравните пример AsyncDemo для WinINet с примером AsyncDemo для WinHTTP.

Эквиваленты WinHTTP функциям WinINet

В следующей таблице перечислены функции WinINet, связанные с стеком клиента HTTP вместе с эквивалентами WinHTTP.

Если приложению требуются функции WinINet, которые не перечислены, не переносите приложение в WinHTTP.

Функция WinINet Эквивалент WinHTTP Заметные изменения
HttpAddRequestHeaders WinHttpAddRequestHeaders Нет.
HttpEndRequest WinHttpReceiveResponse Значение контекста устанавливается с помощью WinHttpSendRequest или WinHttpSetOption. Параметры запроса задаются WinHttpOpenRequest. WinHttpReceiveResponse необходимо вызвать после отправки запроса.
HttpOpenRequest WinHttpOpenRequest Значение контекста задается WinHttpSendRequest или WinHttpSetOption.
HttpQueryInfo WinHttpQueryHeaders Нет.
HttpSendRequest WinHttpSendRequest Значение контекста можно задать с помощью WinHttpSendRequest.
HttpSendRequestEx WinHttpSendRequest Буферы не могут быть предоставлены.
InternetCanonicalizeUrl Нет эквивалента URL-адреса теперь помещаются в каноническую форму в WinHttpOpenRequest.
InternetCheckConnection Нет эквивалента Не реализовано в WinHTTP.
InternetCloseHandle WinHttpCloseHandle Закрытие родительского дескриптора в WinHTTP не рекурсивно закрывает дочерние дескрипторы.
InternetCombineUrl Нет эквивалента URL-адреса можно собрать с помощью функции WinHttpCreateUrl.
ИнтернетПодтверждениеПересеченияЗоны Нет эквивалента Не реализовано в WinHTTP.
InternetConnect WinHttpConnect Значение контекста задается с помощью WinHttpSendRequest или WinHttpSetOption. Параметры запроса устанавливаются с помощью WinHttpOpenRequest. Учетные данные пользователя устанавливаются с помощью WinHttpSetCredentials.
InternetCrackUrl WinHttpCrackUrl Противоположное поведение флага ICU_ESCAPE: с InternetCrackUrlэтот флаг приводит к преобразованию escape-последовательностей (%xx) в символы, но с WinHttpCrackUrlэтот флаг вызывает преобразование символов, которые необходимо экранировать в HTTP-запросе, в escape-последовательности.
InternetCreateUrl WinHttpCreateUrl Нет.
InternetErrorDlg Нет эквивалента Так как WinHTTP предназначен для серверных приложений, он не реализует пользовательский интерфейс.
InternetGetCookie Нет эквивалента WinHTTP не сохраняет данные между сеансами и не может получить доступ к файлам cookie WinINet.
InternetOpen WinHttpOpen Нет.
InternetOpenUrl WinHttpConnect, WinHttpOpenRequest, WinHttpSendRequest, WinHttpReceiveResponse Эта функция доступна в перечисленных функциях WinHTTP.
InternetQueryDataAvailable WinHttpQueryDataAvailable Зарезервированные параметры отсутствуют.
InternetQueryOption WinHttpQueryOption WinHTTP предлагает другой набор параметров из WinINet. Дополнительные сведения и параметры, предлагаемые WinHTTP, см. в разделе флаги параметров.
InternetReadFile WinHttpReadData Никакой.
InternetReadFileEx WinHttpReadData Вместо структуры буфер — это область памяти, адресованная указателем.
InternetSetOption WinHttpSetOption Нет.
InternetSetStatusCallback WinHttpSetStatusCallback Дополнительные сведения см. в разделе "Различные обработки асинхронных запросов".
InternetTimeFromSystemTime WinHttpTimeFromSystemTime Нет.
InternetTimeToSystemTime WinHttpTimeToSystemTime Нет.
InternetWriteFile WinHttpWriteData Нет.

 

Различные обработки асинхронных запросов

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

WinINet

  • Синхронное завершение: если потенциально асинхронный вызов функции WinINet завершается синхронно, параметры OUT функции возвращают результаты операции. При возникновении ошибки получите код ошибки, вызвав GetLastError после вызова функции WinINet.

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

Другими словами, приложение должно дублировать логику для обработки результатов таких операций в двух местах: как сразу после вызова функции, так и в функции обратного вызова.

WinHTTP упрощает эту модель, позволяя реализовать операционную логику только в функции обратного вызова, которая получает уведомление о завершении независимо от того, выполняется ли операция синхронно или асинхронно. Если асинхронная операция включена, параметры OUT функций WinHTTP не возвращают значимые данные и должны иметь значение NULL.

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

WinHTTP

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

  • Асинхронное завершение: когда операция завершается асинхронно, результаты возвращаются в функции обратного вызова, которая выполняется в рабочем потоке.

Хотя большинство ошибок можно обрабатывать полностью в функции обратного вызова, приложения WinHTTP все равно должны быть готовы к тому, что функция вернет FALSE из-за ERROR_INVALID_PARAMETER или другой аналогичной ошибки, полученной вызовом GetLastError.

В отличие от WinINet, которая может выполнять несколько асинхронных операций одновременно, WinHTTP применяет политику одной ожидающей асинхронной операции на дескриптор запроса. Если одна операция находится в ожидании и вызывается другая функция WinHTTP, вторая функция завершается ошибкой и GetLastError возвращает ERROR_INVALID_OPERATION.

WinHTTP упрощает эту модель, позволяя реализовать операционную логику только в функции обратного вызова, которая получает уведомление о завершении независимо от того, выполняется ли операция синхронно или асинхронно. Если асинхронная операция включена, параметры OUT функций WinHTTP не возвращают значимые данные и должны иметь значение NULL.

Различия в уведомлениях обратного вызова WinHTTP

Функция обратного вызова состояния получает обновления о состоянии операций с помощью флагов уведомлений. В WinHTTP уведомления выбираются с помощью параметра dwNotificationFlags функции WinHttpSetStatusCallback. Используйте флаг WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS для получения уведомлений обо всех обновлениях статуса.

Уведомления, указывающие, что определенная операция завершена, называются уведомлениями о завершении или просто завершения. В WinINet каждый раз, когда функция обратного вызова получает завершение, параметр lpvStatusInformation содержит структуру INTERNET_ASYNC_RESULT. В WinHTTP эта структура недоступна для всех завершений. Важно просмотреть справочную страницу для WINHTTP_STATUS_CALLBACK, которая содержит сведения о уведомлениях и типе данных, которые можно ожидать для каждого.

В WinHTTP одно завершение WINHTTP_CALLBACK_STATUS_REQUEST_ERRORуказывает, что операция завершилась ошибкой. Все остальные завершения указывают на успешную операцию.

Как WinINet, так и WinHTTP используют определяемое пользователем значение контекста для передачи информации из основного потока в функцию обратного вызова состояния, которая может выполняться в рабочем потоке. В WinINet значение контекста, используемое функцией обратного вызова состояния, устанавливается путем вызова одной из нескольких функций. В WinHTTP значение контекста задается только с WinHttpSendRequest или WinHttpSetOption. Из-за этого в WinHTTP уведомление может произойти до установки значения контекста. Если функция обратного вызова получает уведомление до установки значения контекста, приложение должно быть готово к получению NULL в параметре dwContext функции обратного вызова.

Различия в проверке подлинности

В WinINet учетные данные пользователя задаются путем вызова функции InternetSetOption, используя код, аналогичный приведенному в следующем примере кода.

// Use the WinINet InternetSetOption function to set the 
// user credentials to the user name contained in strUsername 
// and the password to the contents of strPassword.
       
InternetSetOption( hRequest, INTERNET_OPTION_PROXY_USERNAME, 
                   strUsername, strlen(strUsername) + 1 );

InternetSetOption( hRequest, INTERNET_OPTION_PROXY_PASSWORD, 
                   strPassword, strlen(strPassword) + 1 );

Для обеспечения совместимости учетные данные пользователя можно задать в WinHTTP с помощью функции WinHttpSetOption, но это не рекомендуется, так как она может представлять уязвимость безопасности.

Вместо этого, когда приложение получает код состояния 401 в WinHTTP, рекомендуется сначала определить схему проверки подлинности с помощью WinHttpQueryAuthSchemes и, во-вторых, задать учетные данные с помощью WinHttpSetCredentials. В следующем примере кода показано, как это сделать.

DWORD dwSupportedSchemes;
DWORD dwPrefered;
DWORD dwTarget;

// Obtain the supported and first schemes.
WinHttpQueryAuthSchemes( hRequest, &dwSupportedSchemes, &dwPrefered, &dwTarget );

// Set the credentials before resending the request.
WinHttpSetCredentials( hRequest, dwTarget, dwPrefered, strUsername, strPassword, NULL );

Поскольку в WinHTTP нет эквивалента InternetErrorDlg, приложения, получающие учетные данные через пользовательский интерфейс, должны предоставлять собственный интерфейс.

В отличие от WinINet, WinHTTP не кэширует пароли. Допустимые учетные данные пользователя должны быть предоставлены для каждого запроса.

WinHTTP не поддерживает схему распределенной проверки подлинности паролей (DPA), поддерживаемую WinINet. Однако WinHTTP поддерживает Microsoft Passport 1.4. Дополнительные сведения об использовании проверки подлинности Passport в WinHTTP см. в проверке подлинности Passport в WinHTTP.

WinHTTP не зависит от параметров Internet Explorer для определения политики автоматического входа. Вместо этого параметр автоматического входа устанавливается с помощью WinHttpSetOption. Дополнительные сведения о проверке подлинности в WinHTTP, включая политику автоматического входа, см. в разделе Аутентификация в WinHTTP.

Различия в безопасных HTTP-транзакциях

В WinINet инициируйте безопасный сеанс с помощью HttpOpenRequest или InternetConnect, но в WinHTTP необходимо вызвать WinHttpOpenRequest с помощью флага WINHTTP_FLAG_SECURE.

В безопасной HTTP-транзакции серверные сертификаты могут использоваться для аутентификации сервера перед клиентом. В WinINet, если сертификат сервера содержит ошибки, httpSendRequest завершается ошибкой и содержит сведения об ошибках сертификата.

В WinHttp ошибки сертификата сервера обрабатываются в соответствии с версией следующим образом:

  • Начиная с WinHttp 5.1, если сертификат сервера не проходит проверку или содержит погрешности, вызов WinHttpSendRequest сообщает WINHTTP_CALLBACK_STATUS_SECURE_FAILURE в функции обратного вызова. Если ошибка, созданная WinHttpSendRequest, игнорируется, последующие вызовы WinHttpReceiveResponse завершаются с ошибкой ERROR_WINHTTP_OPERATION_CANCELLED.
  • В WinHTTP 5.0 ошибки в сертификатах сервера по умолчанию не приводят к сбою запроса. Вместо этого ошибки отображаются в функции обратного вызова с уведомлением WINHTTP_CALLBACK_STATUS_SECURE_FAILURE.

На некоторых более ранних платформах WinINet поддерживает протоколы Private Communication Technology (PCT) и (или) Fortezza, хотя и не в Windows XP.

WinHTTP не поддерживает протоколы PCT и Fortezza на любой платформе, а вместо этого использует протокол SSL 2.0, SSL 3.0 или TLS 1.0.