C++编程笔记:使用WinHTTP实现HTTP访问
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
C++编程笔记:使⽤WinHTTP实现HTTP访问
实现HTTP访问的流程包括以下⼏步:
1,⾸先我们打开⼀个Session获得⼀个HINTERNET session句柄;
2,然后我们使⽤这个session句柄与服务器连接得到⼀个HINTERNET connect句柄;
3,然后我们使⽤这个connect句柄来打开Http请求得到⼀个HINTERNET request句柄;
4,这时我们就可以使⽤这个request句柄来发送数据与读取从服务器返回的数据;
5,最后依次关闭request,connect,session句柄。
微软提供了两套http访问的接⼝:WinHTTP和WinINet。
WinHTTP⽐WinINet更加安全和健壮,可以认为WinHTTP是WinINet的升级版本。
这两套API包含了很多相似的函数与宏
定义,访问的流程也是完全类似的(上述5步)。
本⽂主要通过WinHTTP实现post请求⽅法,严格按照上述5个步骤给⼤家进⾏讲解。
1 #include <iostream>
2 #include <tchar.h>
3 #include <string>
4 #include <windows.h>
5 #include <winhttp.h>
6#pragma comment(lib, "winhttp.lib")
7
8using namespace std;
9
10int _tmain(int argc, _TCHAR* argv[])
11 {
12 HINTERNET hSession = NULL;
13 HINTERNET hConnect = NULL;
14 HINTERNET hRequest = NULL;
15
16//1. 初始化⼀个WinHTTP-session句柄,参数1为此句柄的名称
17 hSession = WinHttpOpen(L"csdn@elaine_bao", NULL, NULL, NULL, NULL);
18if (hSession == NULL) {
19 cout<<"Error:Open session failed: "<<GetLastError()<<endl;
20return -1;
21 }
22
23//2. 通过上述句柄连接到服务器,需要指定服务器IP和端⼝号。
若连接成功,返回的hConnect句柄不为NULL
24 hConnect = WinHttpConnect(hSession, L"192.168.50.112", (INTERNET_PORT)8080, 0);
25if (hConnect == NULL) {
26 cout << "Error:Connect failed: " << GetLastError()<<endl;
27return -1;
28 }
29
30//3. 通过hConnect句柄创建⼀个hRequest句柄,⽤于发送数据与读取从服务器返回的数据。
31 hRequest = WinHttpOpenRequest(hConnect, L"Post", L"getServiceInfo", NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, 0);
32//其中参数2表⽰请求⽅式,此处为Post;参数3:给定Post的具体地址,如这⾥的具体地址为http://192.168.50.112/getServiceInfo
33if (hRequest == NULL) {
34 cout << "Error:OpenRequest failed: " << GetLastError() << endl;
35return -1;
36 }
37
38//4-1. 向服务器发送post数据
39//(1) 指定发送的数据内容
40string data = "This is my data to be sent";
41const void *ss = (const char *)data.c_str();
42
43//(2) 发送请求
44 BOOL bResults;
45 bResults = WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, const_cast<void*>(ss), data.length(), data.length(), 0);
46if (!bResults){
47 cout << "Error:SendRequest failed: " << GetLastError() << endl;
48return -1;
49 }
50else{
51//(3)发送请求成功则准备接受服务器的response。
注意:在使⽤ WinHttpQueryDataAvailable和WinHttpReadData前必须使⽤WinHttpReceiveResponse才能access服务器返回的数据
52 bResults = WinHttpReceiveResponse(hRequest, NULL);
53 }
54
55//4-2. 获取服务器返回数据的header信息。
这⼀步我⽤来获取返回数据的数据类型。
56 LPVOID lpHeaderBuffer = NULL;
57 DWORD dwSize = 0;
58if (bResults)
59 {
60//(1) 获取header的长度
61 WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_RAW_HEADERS_CRLF,
62 WINHTTP_HEADER_NAME_BY_INDEX, NULL,
63 &dwSize, WINHTTP_NO_HEADER_INDEX);
64
65//(2) 根据header的长度为buffer申请内存空间
66if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
67 {
68 lpHeaderBuffer = new WCHAR[dwSize / sizeof(WCHAR)];
69
70//(3) 使⽤WinHttpQueryHeaders获取header信息
71 bResults = WinHttpQueryHeaders(hRequest,
72 WINHTTP_QUERY_RAW_HEADERS_CRLF,
73 WINHTTP_HEADER_NAME_BY_INDEX,
74 lpHeaderBuffer, &dwSize,
75 WINHTTP_NO_HEADER_INDEX);
76 }
77 }
78 printf("Header contents: \n%S", lpHeaderBuffer);
79
80//解析上述header信息会发现服务器返回数据的charset为uft-8。
这意味着后⾯需要对获取到的raw data进⾏宽字符转换。
⼀开始由于没有意识到需要进⾏转换所以得到的数据都是乱码。
81//出现乱码的原因是:HTTP在传输过程中是⼆值的,它并没有text或者是unicode的概念。
HTTP使⽤7bit的ASCII码作为HTTP headers,但是内容是任意的⼆值数据,需要根据header中指定的编码⽅式来描述它(通常是Content-Type header) 82//因此当你接收到原始的HTTP数据时,先将其保存到char[] buffer中,然后利⽤WinHttpQueryHearders()获取HTTP头,得到内容的Content-Type,这样你就知道数据到底是啥类型的了,是ASCII还是Unicode或者其他。
83//⼀旦你知道了具体的编码⽅式,你就可以通过MultiByteToWideChar()将其转换成合适编码的字符,存⼊wchar_t[]中。
84//关于乱码的解决⽅案请看4-4
85
86//4-3. 获取服务器返回数据
87 LPSTR pszOutBuffer = NULL;
88 DWORD dwDownloaded = 0; //实际收取的字符数
89 wchar_t *pwText = NULL;
90if (bResults)
91 {
92do
93 {
94//(1) 获取返回数据的⼤⼩(以字节为单位)
95 dwSize = 0;
96if (!WinHttpQueryDataAvailable(hRequest, &dwSize)){
97 cout << "Error:WinHttpQueryDataAvailable failed:" << GetLastError() << endl;
98break;
99 }
100if (!dwSize) break; //数据⼤⼩为0
101
102//(2) 根据返回数据的长度为buffer申请内存空间
103 pszOutBuffer = new char[dwSize + 1];
104if (!pszOutBuffer){
105 cout<<"Out of memory."<<endl;
106break;
107 }
108 ZeroMemory(pszOutBuffer, dwSize + 1); //将buffer置0
109
110//(3) 通过WinHttpReadData读取服务器的返回数据
111if (!WinHttpReadData(hRequest,pszOutBuffer, dwSize, &dwDownloaded)){
112 cout << "Error:WinHttpQueryDataAvailable failed:" << GetLastError() << endl;
113 }
114if (!dwDownloaded)
115break;
116
117 } while (dwSize > 0);
118
119//4-4. 将返回数据转换成UTF8
120 DWORD dwNum = MultiByteToWideChar(CP_ACP, 0, pszOutBuffer, -1, NULL, 0); //返回原始ASCII码的字符数⽬121 pwText = new wchar_t[dwNum]; //根据ASCII码的字符数分配UTF8的空间
122 MultiByteToWideChar(CP_UTF8, 0, pszOutBuffer, -1, pwText, dwNum); //将ASCII码转换成UTF8
123 printf("Received contents: \n%S", pwText);
124 }
125
126
127//5. 依次关闭request,connect,session句柄
128if (hRequest) WinHttpCloseHandle(hRequest);
129if (hConnect) WinHttpCloseHandle(hConnect);
130if (hSession) WinHttpCloseHandle(hSession);
131
132
133return0;
134 }
1 PCSTR pszData = "WinHttpWriteData Example";
2 DWORD dwBytesWritten = 0;
3 BOOL bResults = FALSE;
4 HINTERNET hSession = NULL,
5 hConnect = NULL,
6 hRequest = NULL;
7
8// Use WinHttpOpen to obtain a session handle.
9 hSession = WinHttpOpen( L"A WinHTTP Example Program/1.0",
10 WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
11 WINHTTP_NO_PROXY_NAME,
12 WINHTTP_NO_PROXY_BYPASS, 0);
13
14// Specify an HTTP server.
15if (hSession)
16 hConnect = WinHttpConnect( hSession, L"",
17 INTERNET_DEFAULT_HTTP_PORT, 0);
18
19// Create an HTTP Request handle.
20if (hConnect)
21 hRequest = WinHttpOpenRequest( hConnect, L"PUT",
22 L"/writetst.txt",
23 NULL, WINHTTP_NO_REFERER,
24 WINHTTP_DEFAULT_ACCEPT_TYPES,
250);
26
27// Send a Request.
28if (hRequest)
29 bResults = WinHttpSendRequest( hRequest,
30 WINHTTP_NO_ADDITIONAL_HEADERS,
310, WINHTTP_NO_REQUEST_DATA, 0,
32 (DWORD)strlen(pszData), 0);
33
34// Write data to the server.
35if (bResults)
36 bResults = WinHttpWriteData( hRequest, pszData,
37 (DWORD)strlen(pszData),
38 &dwBytesWritten);
39
40// End the request.
41if (bResults)
42 bResults = WinHttpReceiveResponse( hRequest, NULL);
43
44// Report any errors.
45if (!bResults)
46 printf("Error %d has occurred.\n",GetLastError());
47
48
49// Close any open handles.
50if (hRequest) WinHttpCloseHandle(hRequest);
51if (hConnect) WinHttpCloseHandle(hConnect);
52if (hSession) WinHttpCloseHandle(hSession);。