共用方式為


處理統一資源定位器

統一資源定位器 (URL) 是位於因特網上之資源的位置和存取方法的精簡表示法。 每個 URL 都包含配置(HTTP、HTTPS 或 FTP)和配置特定的字串。 此字串也可以包含目錄路徑、搜尋字串或資源名稱的組合。 WinINet 函式可讓您建立、合併、細分和正式化 URL。 如需 URL 的詳細資訊,請參閱統一資源定位器 (URL) 上的 RFC-1738

URL 函式會以工作導向的方式運作。 未驗證提供給函式之 URL 的內容和格式。 呼叫的應用程式應該追蹤使用這些函式,以確保數據的格式為預期格式。 例如,InternetCanonicalizeUrl 函式會在不使用旗標時,將字元 「%」 轉換成逸出序列 「%25」。 如果在標準 URL 上使用 InternetCanonicalizeUrl,逸出序列 “%25” 會轉換成逸出序列 “%2525”,這樣將無法正常運作。

什麼是標準 URL?

所有 URL 的格式都必須遵循接受的語法和語意,才能透過因特網存取資源。 正規化是將 URL 格式化為符合既定的語法和語意的過程。

必須編碼的字元包括 US-ASCII 編碼字元集中沒有對應圖形字元的任何字元(十六進位 80-FF,這些字元不會用於 US-ASCII 編碼字元集,以及十六進位 00-1F 和 7F,也就是控制字元)、空格“%”(用來編碼其他字元),以及不安全字元 (<, >、“、#、{、}、|、\、^、~、[、]和 ')。

使用 WinINet 函式來處理 URL

下表摘要說明 URL 函式。

功能 描述
InternetCanonicalizeUrl 標準化 URL。
InternetCombineUrl 結合基底網址和相對網址。
InternetCrackUrl 將 URL 字串剖析為元件。
InternetCreateUrl 從元件建立 URL 字串。
InternetOpenUrl 開始擷取 FTP、HTTP 或 HTTPS 資源。

 

正規化 URL

規範化 URL 是將 URL 轉換成接受格式的程式,其可能包含不安全的字元,例如空格、保留字元等等。

InternetCanonicalizeUrl 函式可用來規範 URL。 此函式非常任務導向,因此應用程式應該仔細追蹤其使用方式。 InternetCanonicalizeUrl 不會驗證傳遞至它的 URL 已正式化,且傳回的 URL 有效。

下列五個旗標可控制 internetCanonicalizeUrl如何處理特定 URL。 旗標可以組合使用。 如果未使用旗標,函式預設會編碼 URL。

價值 意義
ICU_BROWSER_MODE 請勿在 “#” 或 “?”之後編碼或譯碼字元,而且不要移除 “?”之後的尾端空格符。 如果未指定此值,則會編碼整個 URL,並移除結尾空格符。
ICU_DECODE 在剖析 URL 之前,將所有 %XX 序列轉換成字元,包括逸出序列。
ICU_ENCODE_SPACES_ONLY 僅編碼空格。
ICU_NO_ENCODE 請勿將不安全字元轉換成逸出序列。
ICU_NO_META 請勿從 URL 移除中繼序列 (例如 “.” 和 “..”。

 

ICU_DECODE旗標只應用於標準化 URL,因為它假設所有 %XX 序列都是逸出碼,並將它們轉換成程式代碼所指示的字元。 如果 URL 中有不屬於逸出程式代碼一部分的 「%」 符號,ICU_DECODE仍會將它視為一個。 此特性可能會導致 InternetCanonicalizeUrl 建立無效的 URL。

若要使用 InternetCanonicalizeUrl 傳回完全譯碼的 URL,必須指定ICU_DECODE和ICU_NO_ENCODE旗標。 假設傳遞到 InternetCanonicalizeUrl 的 URL 已事先進行過正式化。

合併基本 URL 和相對 URL

相對 URL 是相對於絕對基底 URL 之資源位置的精簡表示法。 剖析器必須知道基本 URL,通常包括方案(Scheme)、網路位置和 URL 路徑的一部分。 應用程式可以呼叫 InternetCombineUrl,以結合相對 URL 與其基底 URL。 InternetCombineUrl 也會標準化所產生的 URL。

破解 URL

InternetCrackUrl 函式會將 URL 分成其元件元件,並傳回傳遞至函式之 URL_COMPONENTS 結構所指示的元件。

構成 URL_COMPONENTS 結構的元件是配置編號、主機名、埠號碼、用戶名稱、密碼、URL 路徑和其他資訊(例如搜尋參數)。 配置和埠號碼以外的每個元件都有保存資訊的字串成員,以及保存字串成員長度的成員。 方案和埠號碼只有一個成員儲存對應的值;在所有成功呼叫 InternetCrackUrl 時,方案和埠號碼都會被傳回。

若要取得 URL_COMPONENTS 結構中特定元件的值,儲存該元件字串長度的成員必須設定為非零值。 字串成員可以是緩衝區的位址,或 NULL

如果指標成員包含緩衝區的位址,字串長度成員必須包含該緩衝區的大小。 InternetCrackUrl 會將元件資訊當做緩衝區中的字串傳回,並將字串長度儲存在字串長度成員中。

如果指標成員 NULL,字串長度成員可以設定為任何非零值。 InternetCrackUrl 儲存 URL 字串的第一個字元位址,其中包含元件資訊,並將字串長度設定為與元件相關的 URL 字串其餘部分的字元數。

所有指標成員都會設定為 NULL,並將非零長度成員指向 URL 字串中適當的起點。 儲存在長度成員中的長度必須用來判斷個別元件資訊的結束。

若要正確完成初始化 URL_COMPONENTS 結構,dwStructSize 成員必須設定為 URL_COMPONENTS 結構的大小(以位元組為單位)。

下列範例會傳回編輯框中URL的元件,IDC_PreOpen1,並將元件傳回至清單框,IDC_PreOpenList。 為了只顯示個別元件的資訊,此函式會在字串中元件的信息之後立即複製字元,並暫時將它取代為 NULL

#include <windows.h>
#include <tchar.h>
#include <strsafe.h>
#include <wininet.h>
#include <stdlib.h>

#pragma comment(lib, "wininet.lib")
#pragma comment(lib, "user32.lib")

#define  CRACKER_BUFFER_SIZE           MAX_PATH

// For sample source code implementing the InternetErrorOut( ) 
// function referenced below, see the "Handling Errors" topic  
// under "Using WinInet"
extern BOOL WINAPI InternetErrorOut( HWND hWnd, DWORD dwError,
                                     LPCTSTR szFailingFunctionName );

// Forward declaration of listUrlPart helper functions:
BOOL listURLpart( HWND hDlg, int nListBoxID, 
                  LPTSTR szPartName, LPTSTR part, DWORD partLength );
BOOL listURLpart( HWND hDlg, int nListBoxID, 
                  LPTSTR szPartName, int partValue );

// Static list describing the URL Scheme types 
// enumerated in INTERNET_SCHEME:
TCHAR* schemeType[] =
{
  TEXT( "[Partial URL]" ),                //  0
  TEXT( "[Unknown scheme]" ),             //  1
  TEXT( "[Default scheme]" ),             //  2
  TEXT( "FTP" ),                          //  3
  TEXT( "Gopher" ),                       //  4
  TEXT( "HTTP" ),                         //  5
  TEXT( "HTTPS" ),                        //  6
  TEXT( "File" ),                         //  7
  TEXT( "News" ),                         //  8
  TEXT( "MailTo" ),                       //  9
  TEXT( "Socks" ),                        // 10
  TEXT( "JavaScript" ),                   // 11
  TEXT( "VBScript" )                      // 12
};
#define  CRACKER_SCHEME_TYPE_ARRAY_SIZE      13

BOOL WINAPI Cracker( HWND hDlg, int nURLtextBoxId, int nListBoxId )
{
   int i, j;
   TCHAR* failedFunctionName;
   TCHAR URL_buffer[CRACKER_BUFFER_SIZE];

   URL_COMPONENTS URLparts;

   URLparts.dwStructSize = sizeof( URLparts );

   // The following elements determine which components are displayed
   URLparts.dwSchemeLength    = 1;
   URLparts.dwHostNameLength  = 1;
   URLparts.dwUserNameLength  = 1;
   URLparts.dwPasswordLength  = 1;
   URLparts.dwUrlPathLength   = 1;
   URLparts.dwExtraInfoLength = 1;

   URLparts.lpszScheme     = NULL;
   URLparts.lpszHostName   = NULL;
   URLparts.lpszUserName   = NULL;
   URLparts.lpszPassword   = NULL;
   URLparts.lpszUrlPath    = NULL;
   URLparts.lpszExtraInfo  = NULL;

   SendDlgItemMessage( hDlg, nListBoxId, LB_RESETCONTENT, 0, 0 );
   if( !GetDlgItemText( hDlg, nURLtextBoxId, 
                        URL_buffer, CRACKER_BUFFER_SIZE ) )
   {
       failedFunctionName = TEXT( "GetDlgItemText" );
       goto CrackerError_01;
   }

   if( FAILED( StringCchLength( URL_buffer, CRACKER_BUFFER_SIZE, 
                                (size_t*) &i ) ) )
   {
       failedFunctionName = TEXT( "StringCchLength" );
       goto CrackerError_01;
   }

   if( !InternetCrackUrl( URL_buffer, (DWORD)_tcslen( URL_buffer ), 0, 
                          &URLparts ) )
   {
       failedFunctionName = TEXT( "InternetCrackUrl" );
       goto CrackerError_01;
   }

   failedFunctionName = TEXT( "listURLpart" );

   i = URLparts.nScheme + 2;
   if( ( i >= 0 ) && ( i < CRACKER_SCHEME_TYPE_ARRAY_SIZE ) )
   {
       StringCchLength( schemeType[i], 
                        CRACKER_BUFFER_SIZE, 
                        (size_t*) &j );
       if( !listURLpart( hDlg, nListBoxId, 
                         TEXT("Scheme type"), 
                         schemeType[i], j ))
           goto CrackerError_01;
   }

   if( !listURLpart( hDlg, nListBoxId, TEXT( "Scheme text" ), 
                     URLparts.lpszScheme, 
                     URLparts.dwSchemeLength ) ||
       !listURLpart( hDlg, nListBoxId, TEXT( "Host name" ), 
                     URLparts.lpszHostName, 
                     URLparts.dwHostNameLength) ||
       !listURLpart( hDlg, nListBoxId, TEXT( "Port number" ), 
                     (int) URLparts.nPort ) ||
       !listURLpart( hDlg, nListBoxId, TEXT( "User name" ), 
                     URLparts.lpszUserName, 
                     URLparts.dwUserNameLength) ||
       !listURLpart( hDlg, nListBoxId, TEXT( "Password" ), 
                     URLparts.lpszPassword, 
                     URLparts.dwPasswordLength) ||
       !listURLpart( hDlg, nListBoxId, TEXT( "Path" ), 
                     URLparts.lpszUrlPath, 
                     URLparts.dwUrlPathLength) ||
       !listURLpart( hDlg, nListBoxId, TEXT( "Extra information"), 
                     URLparts.lpszExtraInfo, 
                     URLparts.dwExtraInfoLength))
           goto CrackerError_01;

   return( TRUE );

CrackerError_01:
// For sample source code of the InternetErrorOut( ) function 
// referenced below, see the "Handling Errors" 
// topic under "Using WinInet"
   InternetErrorOut( hDlg, GetLastError( ), failedFunctionName );
   return FALSE;
}

// listURLpart( ) helper function for string parts
BOOL listURLpart( HWND hDlg, int nListBoxId, 
                  LPTSTR szPartName, LPTSTR part, DWORD partLength )
{
  TCHAR outputBuffer[CRACKER_BUFFER_SIZE];
  LPTSTR nextStart;
  size_t nextSize;

  if( partLength == 0 )  // Just skip empty ones
    return( TRUE );

  if( FAILED( StringCchCopyEx( outputBuffer, 
                              (size_t) CRACKER_BUFFER_SIZE,
                               szPartName, &nextStart, 
                               &nextSize, 0 ) ) ||
      FAILED( StringCchCopyEx( nextStart, nextSize, TEXT( ": " ), 
                               &nextStart, &nextSize, 0 ) ) ||
      FAILED( StringCchCopyNEx( nextStart, nextSize, part, 
                                (size_t) partLength,
                                &nextStart, &nextSize, 0 ) ) )
    return( FALSE );

  *nextStart = 0;
  if( SendDlgItemMessage( hDlg, nListBoxId, LB_ADDSTRING, 0, 
                          (LPARAM)outputBuffer ) < 0 )
    return( FALSE );
  return( TRUE );
}

// listURLpart( ) helper function for numeric parts
BOOL listURLpart( HWND hDlg, int nListBoxId, 
                  LPTSTR szPartName, int partValue )
{
  TCHAR outputBuffer[CRACKER_BUFFER_SIZE];

  if( FAILED( StringCchPrintf( outputBuffer, 
                               (size_t) CRACKER_BUFFER_SIZE,
                               TEXT( "%s: %d" ), szPartName, 
                               partValue ) ) ||
      ( SendDlgItemMessage( hDlg, nListBoxId, LB_ADDSTRING, 0, 
                            (LPARAM)outputBuffer ) < 0 ) )
    return( FALSE );
  return( TRUE );
}

建立 URL

InternetCreateUrl 函式會使用 URL_COMPONENTS 結構中的資訊來建立統一資源定位器。

構成 URL_COMPONENTS 結構的元件是配置、主機名、埠號碼、使用者名稱、密碼、URL 路徑和其他資訊(例如搜尋參數)。 除了埠號碼之外,每個元件都有保存資訊的字串成員,以及保存字串成員長度的成員。

對於每個必要元件,指標成員應該包含持有資訊的緩衝區位址。 如果指標成員包含以零結尾字串的位址,則長度成員應設定為零;如果指標成員包含不是以零結尾的字串位址,則長度成員應該設定為字串長度。 任一不需要的元件,其指標成員必須為 NULL

直接存取 URL

您可以使用 InternetOpenUrlInternetReadFile,以及 InternetFindNextFile 函式,直接存取因特網上的 FTP 和 HTTP 資源。 InternetOpenUrl 會在傳遞至函式的 URL 上開啟與資源的連線。 建立此連線時,有兩個可能的步驟。 首先,如果資源是檔案,InternetReadFile 可以下載它;其次,如果資源是目錄,InternetFindNextFile 可以列舉目錄中的檔案(除非使用 CERN Proxy)。 如需 InternetReadFile的詳細資訊,請參閱 讀取檔案。 如需 InternetFindNextFile的詳細資訊,請參閱 尋找下一個檔案

對於需要透過 CERN Proxy 作的應用程式,InternetOpenUrl 可用來存取 FTP 目錄和檔案。 FTP 要求會封裝為類似 HTTP 要求,CERN Proxy 會接受此要求。

InternetOpenUrl 使用由 InternetOpen 函式創建的 HINTERNET 句柄和資源的 URL。 URL 必須包含協定(http:、ftp:、file: (用於本地文件)、或 https: (用於安全超文本傳輸協定))和網路地址(例如 www.microsoft.com)。 URL 也可以包含路徑(例如 /isapi/gomscom.asp?TARGET=/windows/feature/) 和資源名稱(例如,default.htm)。 針對 HTTP 或 HTTPS 要求,可以包含其他標頭。

InternetQueryDataAvailableInternetFindNextFileInternetReadFileInternetSetFilePointer (HTTP 或 HTTPS URL) 只能使用 internetOpenUrl所建立的句柄來下載資源。

下圖說明要與每個功能搭配使用的控制桿。

句柄與函式搭配使用

InternetOpen 所建立的根 HINTERNET 句柄由 InternetOpenUrl使用。 HINTERNET 句柄由 InternetOpenUrl 創建,可以被 InternetQueryDataAvailableInternetReadFileInternetSetFilePointer(僅限 HTTP 或 HTTPS URL)使用。InternetFindNextFile 未在此處顯示。

如需詳細資訊,請參閱 HINTERNET 控制代碼

注意

WinINet 不支援伺服器實作。 此外,不應在服務中使用。 針對伺服器實作或服務,請使用 Microsoft Windows HTTP 服務 (WinHTTP)