您的位置:首页 > 理论基础 > 计算机网络

使用WinINet和WinHTTP实现Http访问

2017-05-03 17:28 676 查看
使用WinINet和WinHTTP实现Http访问

Http访问有两种方式,GET和POST,就编程来说GET方式相对简单点,它不用向服务器提交数据,在这个例程中我使用POST方式,提交数据value1与value2,并从服务器得到他们的和(value1
+ value2)。

为实现Http访问,微软提供了二套API:WinINet,
WinHTTP。WinHTTP比WinINet更加安全和健壮,可以这么认为WinHTTP是WinINet的升级版本。这两套API包含了很多相似的函数与宏定义,呵呵,详细对比请查阅msdn中的文章“Porting
WinINet Applications to WinHTTP
”,在线MSDN连接:http://msdn2.microsoft.com/en-us/library/aa384068.aspx。在这个例程中,通过一个宏的设置来决定是使用WinHttp还是WinINet。代码如下:

#define USE_WINHTTP      //Comment this line to user wininet.

下面来说说实现Http访问的流程(两套API都一样的流程):

1, 首先我们打开一个Session获得一个HINTERNET session句柄;

2, 然后我们使用这个session句柄与服务器连接得到一个HINTERNET connect句柄;

3, 然后我们使用这个connect句柄来打开Http 请求得到一个HINTERNET request句柄;

4, 这时我们就可以使用这个request句柄来发送数据与读取从服务器返回的数据;

5, 最后依次关闭request,connect,session句柄。

 

在这个例程中以上各个流程都进行了简单封装,以便对比两套API函数的些许差异。下面让源代码说话,原工程是一个windows控制台工程,你可以很容易通过拷贝代码重建工程。

 

另:如果你从服务器得到的返回数据是utf8格式的文本数据,你将需要对返回的数据进行转换才能正确显示中文,日文等。仅供参考,转换为ATL CStringW的函数见下:


CStringW GetStringWFromUtf8(const std::string& str)


{


    int len = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), int(str.length()), 0, 0);




    CStringW buf;


    WCHAR*    dd = buf.GetBuffer(len);




    len = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), int(str.length()), dd, len);




    buf.ReleaseBuffer(len);




    return buf;


}

完整代码如下:

  1

// HttpPost.cpp written by l_zhaohui@163.com
  2

// 2007/11/30
  3

#include "stdafx.h"
  4

#include <windows.h>
  5

#include <stdio.h>
  6

#include <stdlib.h>
  7


  8

#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS
  9

#include <atlbase.h>
 10

#include <atlstr.h>
 11


 12

#define USE_WINHTTP    //Comment this line to user wininet.
 13

#ifdef USE_WINHTTP
 14

    #include <winhttp.h>
 15

    #pragma comment(lib, "winhttp.lib")
 16

#else
 17

    #include <wininet.h>
 18

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

#endif
 20

#define BUF_SIZE    (1024)
 21


 22

// CrackedUrl
 23

class CrackedUrl {
 24

    int m_scheme;
 25

    CStringW m_host;
 26

    int m_port;
 27

    CStringW m_path;
 28

public:
 29

    CrackedUrl(LPCWSTR url)
 30

    {
 31

        URL_COMPONENTS uc = { 0};
 32

        uc.dwStructSize = sizeof(uc);
 33


 34

        const DWORD BUF_LEN = 256;
 35


 36

        WCHAR host[BUF_LEN];
 37

        uc.lpszHostName = host;
 38

        uc.dwHostNameLength = BUF_LEN;
 39


 40

        WCHAR path[BUF_LEN];
 41

        uc.lpszUrlPath = path;
 42

        uc.dwUrlPathLength = BUF_LEN;
 43


 44

        WCHAR extra[BUF_LEN];
 45

        uc.lpszExtraInfo = extra;
 46

        uc.dwExtraInfoLength = BUF_LEN;
 47


 48

#ifdef USE_WINHTTP
 49

        if (!WinHttpCrackUrl(url, 0, ICU_ESCAPE, &uc)) {
 50

            printf("Error:WinHttpCrackUrl failed!\n");
 51

        }
 52


 53

#else
 54

        if (!InternetCrackUrl(url, 0, ICU_ESCAPE, &uc)) {
 55

            printf("Error:InternetCrackUrl failed!\n");
 56

        }
 57

#endif
 58

        m_scheme = uc.nScheme;
 59

        m_host = host;
 60

        m_port = uc.nPort;
 61

        m_path = path;
 62

    }
 63


 64

    int GetScheme() const
 65

    {
 66

        return m_scheme;
 67

    }
 68


 69

    LPCWSTR GetHostName() const
 70

    {
 71

        return m_host;
 72

    }
 73


 74

    int GetPort() const
 75

    {
 76

        return m_port;
 77

    }
 78


 79

    LPCWSTR GetPath() const
 80

    {
 81

        return m_path;
 82

    }
 83


 84

    static CStringA UrlEncode(const char* p)
 85

    {
 86

        if (p == 0) {
 87

            return CStringA();
 88

        }
 89


 90

        CStringA buf;
 91


 92

        for (;;) {
 93

            int ch = (BYTE) (*(p++));
 94

            if (ch == '\0') {
 95

                break;
 96

            }
 97


 98

            if (isalnum(ch) || ch == '_' || ch == '-' || ch == '.') {
 99

                buf += (char)ch;
100

            }
101

            else if (ch == ' ') {
102

                buf += '+';
103

            }
104

            else {
105

                char c[16];
106

                wsprintfA(c, "%%%02X", ch);
107

                buf += c;
108

            }
109

        }
110


111

        return buf;
112

    }
113

};
114


115

// CrackedUrl
116

HINTERNET OpenSession(LPCWSTR userAgent = 0)
117

{
118

#ifdef USE_WINHTTP
119

    return WinHttpOpen(userAgent, NULL, NULL, NULL, NULL);;
120

#else
121

    return InternetOpen(userAgent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
122

#endif
123

}
124


125

HINTERNET Connect(HINTERNET hSession, LPCWSTR serverAddr, int portNo)
126

{
127

#ifdef USE_WINHTTP
128

    return WinHttpConnect(hSession, serverAddr, (INTERNET_PORT) portNo, 0);
129

#else
130

    return InternetConnect(hSession, serverAddr, portNo, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
131

#endif
132

}
133


134

HINTERNET OpenRequest(HINTERNET hConnect, LPCWSTR verb, LPCWSTR objectName, int scheme)
135

{
136

    DWORD flags = 0;
137

#ifdef USE_WINHTTP
138

    if (scheme == INTERNET_SCHEME_HTTPS) {
139

        flags |= WINHTTP_FLAG_SECURE;
140

    }
141


142

    return WinHttpOpenRequest(hConnect, verb, objectName, NULL, NULL, NULL, flags);
143


144

#else
145

    if (scheme == INTERNET_SCHEME_HTTPS) {
146

        flags |= INTERNET_FLAG_SECURE;
147

    }
148


149

    return HttpOpenRequest(hConnect, verb, objectName, NULL, NULL, NULL, flags, 0);
150

#endif
151

}
152


153

BOOL AddRequestHeaders(HINTERNET hRequest, LPCWSTR header)
154

{
155

    SIZE_T len = lstrlenW(header);
156

#ifdef USE_WINHTTP
157

    return WinHttpAddRequestHeaders(hRequest, header, DWORD(len), WINHTTP_ADDREQ_FLAG_ADD);
158

#else
159

    return HttpAddRequestHeaders(hRequest, header, DWORD(len), HTTP_ADDREQ_FLAG_ADD);
160

#endif
161

}
162


163

BOOL SendRequest(HINTERNET hRequest, const void* body, DWORD size)
164

{
165

#ifdef USE_WINHTTP
166

    return WinHttpSendRequest(hRequest, 0, 0, const_cast<void*>(body), size, size, 0);
167

#else
168

    return HttpSendRequest(hRequest, 0, 0, const_cast<void*>(body), size);
169

#endif
170

}
171


172

BOOL EndRequest(HINTERNET hRequest)
173

{
174

#ifdef USE_WINHTTP
175

    return WinHttpReceiveResponse(hRequest, 0);
176

#else
177

    // if you use HttpSendRequestEx to send request then use HttpEndRequest in here!
178

    return TRUE;
179

#endif
180

}
181


182

BOOL QueryInfo(HINTERNET hRequest, int queryId, char* szBuf, DWORD* pdwSize)
183

{
184

#ifdef USE_WINHTTP
185

    return WinHttpQueryHeaders(hRequest, (DWORD) queryId, 0, szBuf, pdwSize, 0);
186

#else
187

    return HttpQueryInfo(hRequest, queryId, szBuf, pdwSize, 0);
188

#endif
189

}
190


191

BOOL ReadData(HINTERNET hRequest, void* buffer, DWORD length, DWORD* cbRead)
192

{
193

#ifdef USE_WINHTTP
194

    return WinHttpReadData(hRequest, buffer, length, cbRead);
195

#else
196

    return InternetReadFile(hRequest, buffer, length, cbRead);
197

#endif
198

}
199


200

void CloseInternetHandle(HINTERNET hInternet)
201

{
202

    if (hInternet)
203

    {
204

#ifdef USE_WINHTTP
205

        WinHttpCloseHandle(hInternet);
206

#else
207

        InternetCloseHandle(hInternet);
208

#endif
209

    }
210

}
211


212

int _tmain(int argc, _TCHAR* argv[])
213

{
214

    HINTERNET hSession = 0;
215

    HINTERNET hConnect = 0;
216

    HINTERNET hRequest = 0;
217

    CStringW strHeader(L"Content-type: application/x-www-form-urlencoded\r\n");
218


219

    // Test data
220

    CrackedUrl crackedUrl(L"http://www.easy-creator.net/test2/add.asp");
221

    CStringA strPostData("value1=10&value2=14");
222


223

    // Open session.
224

    hSession = OpenSession(L"HttpPost by l_zhaohui@163.com");
225

    if (hSession == NULL) {
226

        printf("Error:Open session!\n");
227

        return -1;
228

    }
229


230

    // Connect.
231

    hConnect = Connect(hSession, crackedUrl.GetHostName(), crackedUrl.GetPort());
232

    if (hConnect == NULL) {
233

        printf("Error:Connect failed!\n");
234

        return -1;
235

    }
236


237

    // Open request.
238

    hRequest = OpenRequest(hConnect, L"POST", crackedUrl.GetPath(), crackedUrl.GetScheme());
239

    if (hRequest == NULL) {
240

        printf("Error:OpenRequest failed!\n");
241

        return -1;
242

    }
243


244

    // Add request header.
245

    if (!AddRequestHeaders(hRequest, strHeader)) {
246

        printf("Error:AddRequestHeaders failed!\n");
247

        return -1;
248

    }
249


250

    // Send post data.
251

    if (!SendRequest(hRequest, (const char*)strPostData, strPostData.GetLength())) {
252

        printf("Error:SendRequest failed!\n");
253

        return -1;
254

    }
255


256

    // End request
257

    if (!EndRequest(hRequest)) {
258

        printf("Error:EndRequest failed!\n");
259

        return -1;
260

    }
261


262

    char szBuf[BUF_SIZE];
263

    DWORD dwSize = 0;
264

    szBuf[0] = 0;
265


266

    // Query header info.
267

#ifdef USE_WINHTTP
268

    int contextLengthId = WINHTTP_QUERY_CONTENT_LENGTH;
269

    int statusCodeId = WINHTTP_QUERY_STATUS_CODE;
270

    int statusTextId = WINHTTP_QUERY_STATUS_TEXT;
271

#else
272

    int contextLengthId = HTTP_QUERY_CONTENT_LENGTH;
273

    int statusCodeId = HTTP_QUERY_STATUS_CODE;
274

    int statusTextId = HTTP_QUERY_STATUS_TEXT;
275

#endif
276

    dwSize = BUF_SIZE;
277

    if (QueryInfo(hRequest, contextLengthId, szBuf, &dwSize)) {
278

        szBuf[dwSize] = 0;
279

        printf("Content length:[%s]\n", szBuf);
280

    }
281


282

    dwSize = BUF_SIZE;
283

    if (QueryInfo(hRequest, statusCodeId, szBuf, &dwSize)) {
284

        szBuf[dwSize] = 0;
285

        printf("Status code:[%s]\n", szBuf);
286

    }
287


288

    dwSize = BUF_SIZE;
289

    if (QueryInfo(hRequest, statusTextId, szBuf, &dwSize)) {
290

        szBuf[dwSize] = 0;
291

        printf("Status text:[%s]\n", szBuf);
292

    }
293


294

    // read data.
295

    for (;;) {
296

        dwSize = BUF_SIZE;
297

        if (ReadData(hRequest, szBuf, dwSize, &dwSize) == FALSE) {
298

            break;
299

        }
300


301

        if (dwSize <= 0) {
302

            break;
303

        }
304


305

        szBuf[dwSize] = 0;
306

        printf("%s\n", szBuf);    //Output value = value1 + value2
307

    }
308


309

    CloseInternetHandle(hRequest);
310

    CloseInternetHandle(hConnect);
311

    CloseInternetHandle(hSession);
312


313

    return 0;
314

}
315


=========================================================================================

wininet api函数使用经验点滴

一.使用HttpSendRequestEx后,如需使用HttpQueryInfo,需先用HttpEndRequest结束Request

二.BOOL HttpQueryInfo(

    IN HINTERNET hHttpRequest,

    IN DWORD dwInfoLevel,

    IN LPVOID lpvBuffer,

    IN LPDWORD lpdwBufferLength,

    IN OUT LPDWORD lpdwIndex,

);

lpdwBufferLength会返回所需的Buffer大小,因此如果多次使用此函数,需要多次对lpdwBufferLength赋值,否则会出现ERROR_INSUFFICIENT_BUFFER错误

示例程序:

[cpp] view
plain copy

hHttpFile=HttpOpenRequest(hConnect,"POST","/avlab/index.php",NULL,NULL,0,  

    INTERNET_FLAG_DONT_CACHE|INTERNET_FLAG_NO_COOKIES|INTERNET_FLAG_KEEP_CONNECTION  

    |INTERNET_FLAG_RELOAD,0);  

   HttpAddRequestHeaders(hHttpFile,szCookie,-1,HTTP_ADDREQ_FLAG_ADD);  

   HttpAddRequestHeaders(hHttpFile,"Content-Type: application/x-www-form-urlencoded",-1,HTTP_ADDREQ_FLAG_ADD);  

   HttpSendRequestEx(hHttpFile,&struInterIn,NULL,NULL,NULL);  

   HttpEndRequest(hHttpFile,NULL,NULL,NULL);  

  

   nLength=512;//这一句很重要,,因为HttpQueryInfo返回的时候,会改变此值  

   HttpQueryInfo(hHttpFile,HTTP_QUERY_SET_COOKIE,szBuffer,(unsigned long *)&nLength,NULL);  

三.使用InternetReadFile一定要记得比较已经读取的字节数,以确定数据是否已经全部读完

     如果InternetReadFile未把response的数据读完,后续的request会被response数据淹没,而得不到服务端的及时响应或者无响应.这时候再HttpSendRequest,后续的HttpQueryInfo会不成功    

四.字符串操作时,一定要检查返回值,以防后续代码进行非法操作

五.

     如果向网页提交带参数的get或者post命令,网站需要处理时间,其返回网址的内容可能还没有更新过,如果需要获取更新后的内容,需要对更新前后的内容进行比较

六.

 HttpSendRequest或者HttpSendRequestEx发送消息后如果未接受到response,则会返回NULL,Error Code被设为12002,即超时错误,可以使用 InternetSetOption(hHttpFile,INTERNET_OPTION_SEND_TIMEOUT,&timeout,sizeof(DWORD));  设置超时时间

七.

     不能太依赖服务器提供的文件大小,因为有的时候服务器并不提供文件大小,此时如果再使用HttpQueryInfo获取大小,则会出错,GetLastError()返回值为12150
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: