HTTP 会话

WinINet 使你能够访问万维网 (WWW) 上的资源。 可以使用 InternetOpenUrl (直接访问这些资源,有关详细信息,请参阅 直接访问 url) 。

WWW 上的资源是使用 http 访问的。 HTTP 函数处理基础协议,同时允许应用程序访问 WWW 上的信息。 随着 HTTP 协议的发展,基础协议将更新以维护函数行为。

下图显示了与 HTTP 协议一起使用的函数的关系。 带阴影的框表示返回 HINTERNET 句柄的函数,而普通框表示使用由它们所依赖的函数创建的 HINTERNET 句柄的函数。

用于 http 的 wininet 函数

有关详细信息,请参阅 HINTERNET 句柄

使用 WinINet 函数访问 WWW

在 HTTP 会话期间使用以下函数来访问 WWW。

函数 说明
HttpAddRequestHeaders 将 HTTP 请求标头添加到 HTTP 请求句柄。 此函数需要 HttpOpenRequest 创建的句柄。
HttpOpenRequest 打开 HTTP 请求句柄。 此函数需要 InternetConnect 创建的句柄。
HttpQueryInfo 查询有关 HTTP 请求的信息。 此函数需要 HttpOpenRequestInternetOpenUrl 函数创建的句柄。
HttpSendRequest 将指定的 HTTP 请求发送到 HTTP 服务器。 此函数需要 HttpOpenRequest 创建的句柄。
InternetErrorDlg 显示常见 Internet 错误情况的预定义对话框。 此函数需要调用 HttpSendRequest 时使用的句柄。

 

启动与 WWW 的连接

若要开始与 WWW 的连接,应用程序必须在 InternetOpen 返回的根 HINTERNET 上调用 InternetConnect 函数。 InternetConnect 必须通过声明INTERNET_SERVICE_HTTP服务类型来建立 HTTP 会话。 有关使用 InternetConnect 的详细信息,请参阅 使用 InternetConnect

打开请求

HttpOpenRequest 函数会打开 HTTP 请求并返回可供其他 HTTP 函数使用的 HINTERNET 句柄。 与其他开放函数 ((如 FtpOpenFileInternetOpenUrl) )不同, HttpOpenRequest 在调用时不会将请求发送到 Internet。 HttpSendRequest 函数发送请求并通过网络建立连接。

HttpOpenRequest 采用 InternetConnect 创建的 HTTP 会话句柄和 HTTP 谓词、对象名称、版本字符串、引用者、接受类型、标志和上下文值。

HTTP 谓词是请求中使用的字符串。 请求中使用的常见 HTTP 谓词包括 GET、PUT 和 POST。 如果此值设置为 NULLHttpOpenRequest 将使用默认值 GET。

对象名称是一个字符串,其中包含指定 HTTP 谓词的目标对象的名称。 这通常是文件名、可执行模块或搜索说明符。 如果提供的对象名称是空字符串, 则 HttpOpenRequest 将查找默认页面。

版本字符串应包含 HTTP 版本。 如果此参数为 NULL,则函数使用“HTTP/1.1”。

引用者指定从中获取对象名称的文档的地址。 如果此参数为 NULL,则不指定任何引用网站。

包含 accept 类型的 null 终止字符串指示应用程序接受的内容类型。 将此参数设置为 NULL 表示应用程序不接受任何内容类型。 如果提供了空字符串,则应用程序指示它只接受类型为“”text/*“的文档。 值“text/*”表示仅文本文档,而不是图片或其他二进制文件。

标志值控制缓存、Cookie 和安全问题。 对于 Microsoft 网络 (MSN) 、NTLM 和其他类型的身份验证,请设置 INTERNET_FLAG_KEEP_CONNECTION 标志。

如果在对 InternetOpen 的调用中设置了INTERNET_FLAG_ASYNC标志,则应设置非零上下文值以执行正确的异步操作。

以下示例是对 HttpOpenRequest 的示例调用。

hHttpRequest = HttpOpenRequest( hHttpSession, "GET", "", NULL, "", NULL, 0, 0);

添加请求标头

使用 HttpAddRequestHeaders 函数,应用程序可以将一个或多个请求标头添加到初始请求。 此函数允许应用程序将其他自由格式标头追加到 HTTP 请求句柄;它适用于需要精确控制发送到 HTTP 服务器的请求的复杂应用程序。

HttpAddRequestHeaders 需要 HttpOpenRequest 创建的 HTTP 请求句柄,该字符串包含标头、标头的长度和修饰符。

发送请求

HttpSendRequest 建立与 Internet 的连接,并将请求发送到指定的站点。 此函数需要 HttpOpenRequest 创建的 HINTERNET 句柄。 HttpSendRequest 还可以发送其他标头或可选信息。 可选信息通常用于将信息写入服务器的操作,例如 PUT 和 POST。

HttpSendRequest 发送请求后,应用程序可以使用 HttpOpenRequest 创建的 HINTERNET 句柄上的 InternetReadFileInternetQueryDataAvailableInternetSetFilePointer 函数来下载服务器的资源。

将数据发布到服务器

若要将数据发布到服务器,调用 HttpOpenRequest 中的 HTTP 谓词必须是 POST 或 PUT。 然后,包含 POST 数据的缓冲区的地址应传递到 HttpSendRequest 中的 lpOptional 参数。 dwOptionalLength 参数应设置为数据的大小。

还可以使用 InternetWriteFile 函数将数据发布到使用 HttpSendRequestEx 发送的 HINTERNET 句柄上。

获取有关请求的信息

HttpQueryInfo 允许应用程序检索有关 HTTP 请求的信息。 该函数需要 HttpOpenRequestInternetOpenUrl 创建的 HINTERNET 句柄、信息级别值和缓冲区长度。 HttpQueryInfo 还接受一个存储信息的缓冲区和一个从零开始的标头索引,该索引枚举多个具有相同名称的标头。

从 WWW 下载资源

使用 HttpOpenRequest 打开请求并使用 HttpSendRequest 将其发送到服务器后,应用程序可以使用 InternetReadFileInternetQueryDataAvailableInternetSetFilePointer 函数从 HTTP 服务器下载资源。

以下示例下载资源。 函数接受当前窗口的句柄、编辑框的标识号以及由 HttpOpenRequest 创建并由 HttpSendRequest 发送的 HINTERNET。 它使用 InternetQueryDataAvailable 来确定资源的大小,然后使用 InternetReadFile 下载资源。 然后,内容将显示在编辑框中。

int WINAPI Dumper(HWND hX, int intCtrlID, HINTERNET hResource)
{
    LPTSTR lpszData;    // buffer for the data
    DWORD  dwSize;       // size of the data available
    DWORD  dwDownloaded; // size of the downloaded data
    DWORD  dwSizeSum=0;  // size of the data in the textbox
    LPTSTR lpszHolding;  // buffer to merge the textbox data and buffer

    // Set the cursor to an hourglass.
    SetCursor(LoadCursor(NULL,IDC_WAIT));

    // This loop handles reading the data.
    do
    {
        // The call to InternetQueryDataAvailable determines the
        // amount of data available to download.
        if (!InternetQueryDataAvailable(hResource,&dwSize,0,0))
        {
            printf("InternetQueryDataAvailable failed (%d)\n", GetLastError());
            SetCursor(LoadCursor(NULL,IDC_ARROW));
            return FALSE;
        }
        else
        {
            // Allocate a buffer of the size returned by
            // InternetQueryDataAvailable.
            lpszData = new TCHAR[dwSize+1];

            // Read the data from the HINTERNET handle.
            if(!InternetReadFile(hResource,
                                 (LPVOID)lpszData,
                                 dwSize,
                                 &dwDownloaded))
            {
                printf("InternetReadFile failed (%d)\n", GetLastError());
                delete[] lpszData;
                break;
            }
            else
            {
                // Add a null terminator to the end of the data buffer
                lpszData[dwDownloaded]='\0';

                // Allocate the holding buffer.
                lpszHolding = new TCHAR[dwSizeSum + dwDownloaded + 1];

                // Check if there has been any data written
                // to the textbox.
                if (dwSizeSum != 0)
                {
                    // Retrieve the data stored in the textbox if any
                    GetDlgItemText(hX,intCtrlID,
                                   (LPTSTR)lpszHolding,
                                   dwSizeSum);

                    // Add a null terminator at the end of the
                    // textbox data.
                    lpszHolding[dwSizeSum]='\0';
                }
                else
                {
                    // Make the holding buffer an empty string.
                    lpszHolding[0]='\0';
                }

                size_t cchDest = dwSizeSum + dwDownloaded + dwDownloaded + 1;
                LPTSTR* ppszDestEnd = 0;
                size_t* pcchRemaining = 0;

                // Add the new data to the holding buffer
                HRESULT hr = StringCchCatEx(lpszHolding,
                                            cchDest,
                                            lpszData,
                                            ppszDestEnd,
                                            pcchRemaining,
                                            STRSAFE_NO_TRUNCATION);

                if(SUCCEEDED(hr))
                {
                    // Write the holding buffer to the textbox.
                    SetDlgItemText(hX,intCtrlID,(LPTSTR)lpszHolding);

                    // Delete the two buffers.
                    delete[] lpszHolding;
                    delete[] lpszData;

                    // Add the size of the downloaded data to the
                    // textbox data size.
                    dwSizeSum = dwSizeSum + dwDownloaded + 1;

                    // Check the size of the remaining data.
                    // If it is zero, break.
                    if (dwDownloaded == 0)
                        break;
                    else
                    {
                    //  TODO: Insert error handling code here.
                    }
                }
            }
        }
    }
    while(TRUE);

    // Close the HINTERNET handle.
    InternetCloseHandle(hResource);

    // Set the cursor back to an arrow.
    SetCursor(LoadCursor(NULL,IDC_ARROW));

    return TRUE;
}

注意

WinINet 不支持服务器实现。 此外,不应从服务使用它。 对于服务器实现或服务,请使用 Microsoft Windows HTTP Services (WinHTTP)