使用WinINet和WinHTTP实现Http访问

转自:http://blog.csdn.net/whatday/article/details/38093091

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

为实现Http访问,微软提供了二APIWinINet, WinHTTPWinHTTPWinINet更加安全和健壮可以这么认为WinHTTPWinINet的升级版本这两套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, 最后依次关闭requestconnectsession句柄。

 

在这个例程中以上各个流程都进行了简单封装,以便对比两套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;
 28public:
 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
  1. hHttpFile=HttpOpenRequest(hConnect,"POST","/avlab/index.php",NULL,NULL,0,  
  2.     INTERNET_FLAG_DONT_CACHE|INTERNET_FLAG_NO_COOKIES|INTERNET_FLAG_KEEP_CONNECTION  
  3.     |INTERNET_FLAG_RELOAD,0);  
  4.    HttpAddRequestHeaders(hHttpFile,szCookie,-1,HTTP_ADDREQ_FLAG_ADD);  
  5.    HttpAddRequestHeaders(hHttpFile,"Content-Type: application/x-www-form-urlencoded",-1,HTTP_ADDREQ_FLAG_ADD);  
  6.    HttpSendRequestEx(hHttpFile,&struInterIn,NULL,NULL,NULL);  
  7.    HttpEndRequest(hHttpFile,NULL,NULL,NULL);  
  8.   
  9.    nLength=512;//这一句很重要,,因为HttpQueryInfo返回的时候,会改变此值  
  10.    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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
WinHTTP提供以下功能: WinHttpAddRequestHeaders 向HTTP请求句柄添加一个或多个HTTP请求标头。 WinHttpCheckPlatform 确定WinHTTP是否支持当前平台。 WinHttpCloseHandle 关闭单个 HINTERNET句柄。 WinHttpConnect 指定HTTP请求的初始目标服务器。 WinHttpCrackUrl 将URL分为其组成部分,例如主机名和路径。 WinHttpCreateProxyResolver 创建WinHttpGetProxyForUrlEx使用的句柄。 WinHttpCreateUrl 从组件部分创建URL,例如主机名和路径。 WinHttpDetectAutoProxyConfigUrl 查找代理自动配置(PAC)文件的URL。此功能报告PAC文件的URL,但不下载该文件。 WinHttpFreeProxyResult 释放从以前的调用WinHttpGetProxyResult检索的数据。 WinHttpGetDefaultProxyConfiguration 从注册表中检索默认的WinHTTP代理配置。 WinHTTPGetIEProxyConfigForCurrentUser 获取当前用户的Internet Explorer(IE)代理配置。 WinHttpGetProxyForUrl 检索指定URL的代理信息。 WinHttpGetProxyForUrlEx 检索指定URL的代理信息。 WinHttpGetProxyResult 检索到调用的结果WinHttpGetProxyForUrlEx。 WinHttpOpen 初始化应用程序对WinHTTP功能的使用WinHttpOpenRequest 创建HTTP请求句柄。 WinHttpQueryAuthSchemes 返回服务器支持的授权方案。 WinHttpQueryDataAvailable 返回可立即与读取数据的字节数 WinHttpReadData。 WinHttpQueryHeaders 检索与HTTP请求相关联的头信息。 WinHttpQueryOption 在指定的句柄上查询Internet选项。 WinHttpReadData 从WinHttpOpenRequest函数打开的句柄中读取数据 。 WinHttpReceiveResponse 结束由WinHttpSendRequest启动的HTTP请求 。 WinHttpResetAutoProxy 重置自动代理。 WinHttpSendRequest 将指定的请求发送到HTTP服务器。 WinHttpSetCredentials 将所需的授权凭证传递给服务器。 WinHttpSetDefaultProxyConfiguration 在注册表中设置默认的WinHTTP代理配置。 WinHttpSetOption 设置Internet选项。 WinHttpSetStatusCallback 设置WinHTTP可以在操作过程中进行调用的回调函数。 WinHttpSetTimeouts 设置涉及HTTP事务的各种超时。 WinHttpTimeFromSystemTime 根据HTTP版本1.0规范格式化日期和时间。 WinHttpTimeToSystemTime 获取HTTP时间/日期字符串并将其转换为 SYSTEMTIME结构。 WinHttpWriteData 将请求数据写入HTTP服务器。 WinHttpWebSocketClose 关闭WebSocket连接。 WinHttpWebSocketCompleteUpgrade 完成由WinHttpSendRequest启动的WebSocket握手。 WinHttpWebSocketQueryCloseStatus 获取服务器发送的关闭状态。 WinHttpWebSocketReceive 从WebSocket连接接收数据。 WinHttpWebSocketSend 通过WebSocket连接发送数据。 WinHttpWebSocketShutdown 向WebSocket连接发送关闭框架
使用JavaScript使用WinINet的方式访问网页,可以按照以下步骤进行: 1. 引入ActiveXObject对象:在HTML文档中,使用<script>标签引入JavaScript代码,并在代码中定义一个ActiveXObject对象。ActiveXObject对象在Windows操作系统中用于创建COM组件。 2. 创建WinINet对象:使用ActiveXObject对象的createObject方法创建一个WinINet对象,该对象提供了与WinINet库进行交互的方法和属性。 3. 设置WinINet对象的属性:通过调用WinINet对象的属性,可以配置请求的各种参数。例如,可以设置请求的URL、请求的方法(GET或POST)、请求的头部信息等。 4. 发送请求:使用WinINet对象的open和send方法发送请求。open方法用于指定请求的方法和URL,send方法用于发送请求并接收响应。 5. 处理响应:可以通过WinINet对象的responseBody属性来获取响应的内容。如果需要解析HTML页面,可以使用DOM解析器或正则表达式对响应进行处理。 6. 关闭WinINet对象:在请求和处理响应完成后,使用WinINet对象的close方法关闭与Web服务器的连接。 需要注意的是,使用WinINet方式访问网页可能会受到安全策略的限制。在某些浏览器中,会对ActiveXObject对象的使用进行限制或阻止。此外,对于跨域请求,可能需要设置安全设置以允许跨域访问。 以上是使用JavaScript通过WinINet方式访问网页的基本步骤。具体的实现可能因浏览器和具体的网页环境而有所不同,需要根据实际情况进行调整和适配。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值