將 WinINet 應用程式移植到 WinHTTP
Microsoft Windows HTTP Services (WinHTTP) 是以需要存取 HTTP 用戶端堆疊的仲介層和後端伺服器應用程式為目標。 Microsoft Windows Internet (WinINet) 為用戶端應用程式提供 HTTP 用戶端堆疊,以及存取檔案傳輸通訊協定 (FTP) 、SOCKSv4 和 Gopher 通訊協定。 此概觀可協助判斷將 WinINet 應用程式移植到 WinHTTP 是否很有説明。 它也會描述特定的轉換需求。
移植 WinINet 應用程式之前要考慮的事項
如果您的應用程式受益于下列專案,請考慮將您的 WinINet 應用程式移植到 WinHTTP:
- 伺服器安全的 HTTP 用戶端堆疊。
- 最小化的堆疊使用量。
- 伺服器應用程式的延展性。
- 平臺相關 API 的相依性較少。
- 支援執行緒模擬。
- 服務易記的 HTTP 堆疊。
- 存取可編寫腳本的 WinHttpRequest 物件。
如果 WinINet 應用程式必須支援下列一或多個專案,請勿考慮將您的 WinINet 應用程式移植到 WinHTTP:
- 來自 HTTP 堆疊的 FTP 或 Gopher 通訊協定。
- 支援 SOCKSv4 通訊協定,以便與 SOCKS Proxy 通訊。
- 自動撥號服務。
如果您決定將應用程式移植到 WinHTTP,下列各節會引導您完成轉換程式。
針對 WinINet 和 WinHTTP 的範例應用程式,請比較 WinINet 的 AsyncDemo 範例與 WinHTTP 的 AsyncDemo 範例。
WinHTTP 相當於 WinINet 函式
下表列出與 HTTP 用戶端堆疊相關的 WinINet 函式與 WinHTTP 對等專案。
如果您的應用程式需要未列出的 WinINet 函式,請勿將應用程式移植到 WinHTTP。
非同步要求的處理方式不同
請注意,在 WinINet 和 WinHTTP 中,某些函式可以同步或非同步完成非同步要求。 您的應用程式必須處理任一情況。 WinINet 和 WinHTTP 如何處理這些潛在的非同步函式有顯著差異。
WinINet
同步完成:如果潛在的非同步 WinINet 函式呼叫以同步方式完成,則函式的 OUT 參數會傳回作業的結果。 發生錯誤時,請在 WinINet 函數呼叫之後呼叫 GetLastError 來擷取錯誤碼。
非同步完成:如果潛在的非同步函式呼叫以非同步方式完成,作業的結果和任何錯誤都可以在回呼函式中存取。 回呼函式是在背景工作執行緒上執行,而不是在進行初始函式呼叫的執行緒上執行。
換句話說,您的應用程式必須重複邏輯,才能在兩個位置處理這類作業的結果:在函式呼叫和回呼函式中緊接在之後。
WinHTTP 可讓您只在回呼函式中實作操作邏輯,以簡化此模型,不論作業是同步還是非同步完成,都會接收完成通知。 啟用非同步作業時,WinHTTP 函式的 OUT 參數不會傳回有意義的資料,而且必須設定為 Null。
從應用程式的觀點來看,WinHTTP 中非同步和同步完成之間的唯一顯著差異在於執行回呼函式。
WinHTTP
同步完成:當作業同步完成時,結果會在與原始函數呼叫相同的執行緒中執行的回呼函式中傳回。
非同步完成:當作業以非同步方式完成時,結果會在背景工作執行緒中執行的回呼函式中傳回。
雖然大部分的錯誤也可以完全在回呼函式內處理,但由於呼叫GetLastError所擷取的ERROR_INVALID_PARAMETER或類似錯誤,WinHTTP 應用程式仍必須準備好讓函式傳回FALSE。
不同于 WinINet,它可以同時執行多個非同步作業,WinHTTP 會針對每個要求控制碼強制執行一個擱置非同步作業的原則。 如果某個作業擱置,且呼叫另一個 WinHTTP 函式,則第二個函式會失敗,而 GetLastError 會傳回ERROR_INVALID_OPERATION。
WinHTTP 可讓您只在回呼函式中實作操作邏輯,以簡化此模型,不論作業是同步還是非同步完成,都會接收完成通知。 啟用非同步作業時,WinHTTP 函式的 OUT 參數不會傳回有意義的資料,而且必須設定為 Null。
WinHTTP 回呼通知的差異
狀態回呼函式會透過通知旗標接收作業狀態的更新。 在 WinHTTP 中,會使用WinHttpSetStatusCallback函式的dwNotificationFlags參數來選取通知。 使用 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 中,可以在設定內容值之前發生通知。 如果回呼函式在設定內容值之前收到通知,應用程式必須準備好在回呼函式的dwCoNtext參數中接收Null。
驗證差異
在 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 );
為了相容性,使用者認證同樣可以使用 WinHttpSetOption 函式在 WinHTTP 中設定,但不建議這麼做,因為它可能會造成安全性弱點。
相反地,當應用程式在 WinHTTP 中收到 401 狀態碼時,建議的設定認證方法是先使用 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 不支援 WinINet 支援的分散式密碼驗證 (DPA) 配置。 不過,WinHTTP 支援 Microsoft Passport 1.4。 如需在 WinHTTP 中使用 Passport 驗證的詳細資訊,請參閱 WinHTTP 中的 Passport 驗證。
WinHTTP 不依賴 Internet Explorer 設定來判斷自動登入原則。 而是使用 WinHttpSetOption設定自動登入原則。 如需 WinHTTP 中驗證的詳細資訊,包括自動登入原則,請參閱 WinHTTP 中的驗證。
安全 HTTP 交易的差異
在 WinINet 中,使用HttpOpenRequest或InternetConnect起始安全會話,但在 WinHTTP 中,您必須使用WINHTTP_FLAG_SECURE旗標呼叫WinHttpOpenRequest。
在安全的 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 支援私人通訊技術 (PCT) 和/或 Fortezza 通訊協定,但不是在 Windows XP 上。
WinHTTP 不支援任何平臺上的 PCT 和 Fortezza 通訊協定,而是依賴安全通訊端層 (SSL) 2.0、SSL 3.0 或傳輸層安全性 (TLS) 1.0。