WinHTTP 会话概览
The Microsoft Windows HTTP Services (WinHTTP) exposes a set of C/C++ functions that enable your application to access HTTP resources on the Web. This topic provides an overview of how these functions are used to interact with an HTTP server.
微软的HTTP服务(WinHTTP)暴露了一些C++函数,这些函数能让你的程序访问Web网络上的HTTP资源。这篇文章告诉你怎么使用这些函数和HTTP服务器进行交互。
- Using the WinHTTP API to Access the Web
- Initializing WinHTTP
- Opening a Request
- Adding Request Headers
- Sending a Request
- Posting Data to the Server
- Getting Information About a Request
- Downloading Resources from the Web
使用 WinHTTP API 访问 Web
The following diagram shows the order in which WinHTTP functions are typically called when interacting with an HTTP server. The shaded boxes represent functions that generate anHINTERNET handle, while the plain boxes represent functions that use those handles.
下面的流程图显示了和HTTP服务器使用WinHTTP函数的典型应用。带阴影的框表示这些函数会产生HINTERNET句柄,白框中的函数会用到这些句柄。
初始化 WinHTTP
Before interacting with a server, WinHTTP must be initialized by calling WinHttpOpen. WinHttpOpen creates a session context to maintain details about the HTTP session, and returns a session handle.Using this handle, theWinHttpConnect function is then able to specify a target HTTP or Secure Hypertext Transfer Protocol (HTTPS) server.
开始和服务器交互前,WinHTTP必须使用WinHttpOpen进行初始化,WinHttpOpen会创建一个会话Context,这个会话Context包含了HTTP会话的细节,并且把这个会话Context的句柄返回。使用这个句柄,WinHttpConnect函数就可以指定一个目标HTTP或HTTPS服务器。
注意 对 WinHttpConnect的调用不会立即产生与HTTP服务器的连接请求,连接请求实在请求具体的资源时产生的。
打开一个请求
The WinHttpOpenRequest function opens an HTTP request for a particular resource and returns anHINTERNET handle that can be used by the other HTTP functions. WinHttpOpenRequest does not send the request to the server when called. TheWinHttpSendRequest function actually establishes a connection over the network and sends the request.
WinHttpOpenRequest函数为特定的资源打开一个HTTP请求,然后返回一个HINTERNET句柄,这个句柄可以被其他HTTP函数使用。WinHttpOpenRequest也不会向服务器发送数据。WinHttpSendRequest函数才会与服务器建立连接并发送请求。
The following example shows a sample call to WinHttpOpenRequest that uses the default options.
下面是使用默认参数调用WinHttpOpenRequest的例子。
HINTERNET hRequest = WinHttpOpenRequest( hConnect, L"GET", NULL, NULL, NULL, NULL, 0);
添加请求头部
The WinHttpAddRequestHeaders function allows an application to append additional free-format request headers to the HTTP request handle. It is intended for use by sophisticated applications that require precise control over the requests sent to the HTTP server.
WinHttpAddRequestHeaders函数允许应用程序向HTTP请求中添加各种格式的头部信息。这样让客户端与服务器实现复杂应用与精细控制。
The WinHttpAddRequestHeaders function requires an HTTP request handle created byWinHttpOpenRequest, a string that contains the headers, the length of the headers, and any modifiers.
WinHttpAddRequestHeaders函数需要一个WinHttpOpenRequest产生的HTTP请求句柄,
The following modifiers can be used with WinHttpAddRequestHeaders.
WinHttpAddRequestHeaders可以实现下面改变
Modifier | Description |
---|---|
WINHTTP_ADDREQ_FLAG_ADD | Adds the header if it does not exist. Used with WINHTTP_ADDREQ_FLAG_REPLACE. 如果头部不存在,添加它 |
WINHTTP_ADDREQ_FLAG_ADD_IF_NEW | Adds the header only if it does not already exist; otherwise, an error is returned. 如果头部确实不存在才添加,否则返回错误。 |
WINHTTP_ADDREQ_FLAG_COALESCE | Merges headers of the same name. 对同名头部信息进行融合 |
WINHTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA | Merges headers of the same name using a comma. For example, adding "Accept: text/*" followed by "Accept: audio/*" with this flag forms the single header "Accept: text/*, audio/*", causing the first header found to be merged. It is up to the calling application to ensure a cohesive scheme with respect to merged/separate headers. |
WINHTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON | Merges headers of the same name using a semicolon. |
WINHTTP_ADDREQ_FLAG_REPLACE | Replaces or removes a header. If the header value is empty and the header is found, it is removed. If the header value is not empty, the header value is replaced. |
发送请求
The WinHttpSendRequest function establishes a connection to the server and sends the request to the specified site. This function requires anHINTERNET handle created by WinHttpOpenRequest. WinHttpSendRequest can also send additional headers or optional information. The optional information is generally used for operations that write information to the server, such as PUT and POST.
WinHttpSendRequest函数与服务器建立一个连接,这个函数需要使用WinHttpOpenRequest产生的句柄。WinHttpSendRequest也可以发送附加头部或可选信息,这些附加信息一般是用来向服务器写信息的,例如PUT或者POST。
After the WinHttpSendRequest function sends the request, the application can use theWinHttpReadData and WinHttpQueryDataAvailable functions on the HINTERNET handle to download the server's resources.
WinHttpSendRequest函数发送数据后,应用程序可以使用WinHttpReadData和WinHttpQueryDataAvailable函数,在HINTERNET句柄上下载服务器资源。
向服务器发送数据
To post data to a server, the HTTP verb in the call to WinHttpOpenRequest must be either POST or PUT. When WinHttpSendRequest is called, the dwTotalLength parameter should be set to the size of the data in bytes. Then useWinHttpWriteData to post the data to the server.
要想服务器发送数据,WinHttpOpenRequest的HTTP verb参数必须是POST或PUT。当调用WinHttpSendRequest时,dwTotalLength参数应该设置为要发送数据的byte大小。然后使用WinHttpWriteData向服务器发送数据。
Alternatively, set the lpOptional parameter of WinHttpSendRequest to the address of a buffer that contains data to post to the server. When using this technique, you must set both thedwOptionalLength anddwTotalLength parameters of WinHttpSendRequest to be the size of the data being posted. CallingWinHttpSendRequest in this manner eliminates the need to callWinHttpWriteData.
另外,设置WinHttpSendRequest的lpOptional参数为一个缓冲,这个缓冲中包含要发送的数据。当使用这项技术时,你必须设置WinHttpSendRequest中的dwOptionalLength 和dwTotalLength参数,这些参数由要发送的数据决定。调用WinHttpSendRequest后需要调用WinHttpWriteData。
获取请求后的信息
The WinHttpQueryHeaders function allows an application to retrieve information about an HTTP request. The function requires anHINTERNET handle created by WinHttpOpenRequest, an information level value, and a buffer length.WinHttpQueryHeaders also accepts a buffer that stores the information and a zero-based header index that enumerates multiple headers with the same name.
WinHttpQueryHeaders函数允许应用获取HTTP请求中的信息,这个函数需要WinHttpOpenRequest产生的请求句柄,信息级别值和缓冲长度。WinHttpQueryHeaders也接受一个缓冲,这个缓冲中存储着一些信息,和同名的以0序号开始的头部信息。
Use any of the information level values found on the Query Info Flags page with a modifier to control the format in which the information is stored in thelpvBuffer parameter ofWinHttpQueryHeaders.
使用任意可在Query Info Flags页找到的水平值来控制存在WinHttpQueryHeaders函数的lpvBuffer参数里的格式。
从Web上下载资源
After opening a request with the WinHttpOpenRequest function, sending it to the server with WinHttpSendRequest, and preparing the request handle to receive a response withWinHttpReceiveResponse, the application can use the WinHttpReadData and WinHttpQueryDataAvailable functions to download the resource from the HTTP server.
在使用WinHttpOpenRequest打开资源后,使用WinHttpSendRequest向服务器发送请求,准备好WinHttpReceiveResponse的句柄来获取服务器响应。可以使用WinHttpReadData and WinHttpQueryDataAvailable从服务器下载资源。
The following sample code shows how to download a resource with secure transaction semantics. The sample code initializes the WinHTTP application programming interface (API), selects a target HTTPS server, and then opens and sends a request for this secure resource. WinHttpQueryDataAvailable is used with the request handle to determine how much data is available for download, and thenWinHttpReadData is used to read that data. This process is repeated until the entire document has been retrieved and displayed.
下面例程中展示了一个如何使用安全语法下载资源,这个例程初始化WinHTTP程序,选择目标HTTPS服务器,然后打开,发送请求。WinHttpQueryDataAvailable被用来探查有多少数据需要下载,然后使用WinHttpReadData获取这些数据,这个过程一直重复,直到整个文档被下载并且展示。
#include <windows.h> #include <winhttp.h> #include <stdio.h> #pragma comment(lib,"Winhttp.lib") int main() { 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"192.168.1.101", 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 ); return 0; } PS:自己编译时,发现程序会返回12175错误,下面是12175的错误解决方法,加在 if( hConnect ) hRequest = WinHttpOpenRequest( hConnect, L"GET", NULL, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE ); 之后就可以了。 ------------------------------------------------------------------
DWORD
dwFlags;
DWORD
dwBuffLen =
sizeof
(dwFlags);
WinHttpQueryOption (hRequest, WINHTTP_OPTION_SECURITY_FLAGS,
(
LPVOID
)&dwFlags, &dwBuffLen);
dwFlags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA;
dwFlags |= SECURITY_FLAG_IGNORE_CERT_DATE_INVALID;
dwFlags |= SECURITY_FLAG_IGNORE_CERT_CN_INVALID;
// dwFlags |= SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE;
WinHttpSetOption (hRequest, WINHTTP_OPTION_SECURITY_FLAGS,
&dwFlags,
sizeof
(dwFlags) );