WinHTTP 會話概觀

Microsoft Windows HTTP Services (WinHTTP) 會公開一組 C/C++ 函式,讓應用程式能夠存取網路上的 HTTP 資源。 本主題提供如何使用這些函式來與 HTTP 伺服器互動的概觀。

使用 WinHTTP API 存取 Web

下圖顯示與 HTTP 伺服器互動時,通常會呼叫 WinHTTP 函式的順序。 陰影方塊代表產生 HINTERNET 控制碼的函式,而純文字方塊則代表使用這些控制碼的函式。

建立控制碼的函式

初始化 WinHTTP

在與伺服器互動之前,必須先呼叫 WinHttpOpen 來初始化 WinHTTP WinHttpOpen 會建立會話內容來維護 HTTP 會話的詳細資料,並傳回會話控制碼。 使用此控制碼時, WinHttpConnect 函式就可以指定目標 HTTP 或安全超文字傳輸通訊協定 (HTTPS) 伺服器。

注意

呼叫 WinHttpConnect 不會在對特定資源提出要求之前,產生與 HTTP 伺服器的實際連線。

 

開啟要求

WinHttpOpenRequest函式會開啟特定資源的 HTTP 要求,並傳回其他 HTTP 函式可以使用的HINTERNET控制碼。 WinHttpOpenRequest 不會在呼叫時將要求傳送至伺服器。 WinHttpSendRequest函式實際上會透過網路建立連線,並傳送要求。

下列範例示範使用預設選項的 WinHttpOpenRequest 呼叫範例。

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

新增要求標頭

WinHttpAddRequestHeaders函式可讓應用程式將額外的自由格式要求標頭附加至 HTTP 要求控制碼。 它適用于需要精確控制傳送至 HTTP 伺服器之要求的複雜應用程式。

WinHttpAddRequestHeaders函式需要WinHttpOpenRequest所建立的 HTTP 要求控制碼、包含標頭的字串、標頭的長度,以及任何修飾詞。

下列修飾詞可以搭配 WinHttpAddRequestHeaders使用。

修飾詞 Description
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函式會建立與伺服器的連線,並將要求傳送至指定的月臺。 此函式需要WinHttpOpenRequest所建立的HINTERNET控制碼。 WinHttpSendRequest 也可以傳送其他標頭或選擇性資訊。 選擇性資訊通常用於將資訊寫入伺服器的作業,例如 PUT 和 POST。

在 WinHttpSendRequest函式傳送要求之後,應用程式可以使用HINTERNET控制碼上的WinHttpReadDataWinHttpQueryDataAvailable函式來下載伺服器的資源。

將資料張貼到伺服器

若要將資料張貼到伺服器,呼叫 WinHttpOpenRequest中的HTTP 動詞命令必須是 POST 或 PUT。 呼叫 WinHttpSendRequest 時, dwTotalLength 參數應該設定為以位元組為單位的資料大小。 然後使用 WinHttpWriteData 將資料張貼到伺服器。

或者,將WinHttpSendRequestlpOptional參數設定為包含要張貼至伺服器的資料的緩衝區位址。 使用這項技術時,您必須將WinHttpSendRequestdwOptionalLengthdwTotalLength參數設定為所張貼的資料大小。 以這種方式呼叫 WinHttpSendRequest 可免除呼叫 WinHttpWriteData的需求。

取得要求的相關資訊

WinHttpQueryHeaders函式可讓應用程式擷取 HTTP 要求的相關資訊。 函式需要WinHttpOpenRequest、資訊層級值和緩衝區長度所建立的HINTERNET控制碼。 WinHttpQueryHeaders 也接受儲存資訊的緩衝區,以及以零起始的標頭索引,列舉具有相同名稱的多個標頭。

使用 [查詢資訊旗標] 頁面上找到的任何資訊層級值搭配 修飾詞來控制資訊儲存在WinHttpQueryHeaderslpvBuffer參數中的格式。

從 Web 下載資源

使用 WinHttpOpenRequest 函式開啟要求之後,使用 WinHttpSendRequest將它傳送至伺服器,並準備要求控制碼以接收與 WinHttpReceiveResponse的回應,應用程式可以使用 WinHttpReadDataWinHttpQueryDataAvailable 函式,從 HTTP 伺服器下載資源。

下列範例程式碼示範如何下載具有安全交易語意的資源。 範例程式碼會初始化 WinHTTP 應用程式開發介面 (API) 、選取目標 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 );