├── HttpClient.cpp ├── HttpClient.h └── README.md /HttpClient.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * WinInet封装类,可用于windows上http请求, HttpClient.cpp 3 | * zhangyl 2016.07.15 mail: balloonwj@qq.com 4 | */ 5 | #include "HttpClient.h" 6 | 7 | CHttpClient::CHttpClient(void) 8 | { 9 | m_hInternet = NULL; 10 | m_hConnect = NULL; 11 | m_hRequest = NULL; 12 | 13 | m_hCompleteEvent = NULL; 14 | m_hCancelEvent = NULL; 15 | 16 | m_dwConnectTimeOut = 60 * 1000; 17 | m_dwContext = 0; 18 | } 19 | 20 | CHttpClient::~CHttpClient(void) 21 | { 22 | CloseRequest(); 23 | } 24 | 25 | 26 | // 打开HTTP请求函数 27 | BOOL CHttpClient::OpenRequest(LPCTSTR lpszUrl, HTTP_REQ_METHOD nReqMethod/* = REQ_METHOD_GET*/) 28 | { 29 | TCHAR szScheme[INTERNET_MAX_URL_LENGTH] = { 0 }; 30 | TCHAR szHostName[INTERNET_MAX_URL_LENGTH] = { 0 }; 31 | TCHAR szUrlPath[INTERNET_MAX_URL_LENGTH] = { 0 }; 32 | 33 | WORD nPort = 0; 34 | DWORD dwAccessType; 35 | 36 | LPCTSTR lpszProxy; 37 | // 解析Url 38 | BOOL bRet = ParseURL(lpszUrl, szScheme, INTERNET_MAX_URL_LENGTH, szHostName, INTERNET_MAX_URL_LENGTH, nPort, szUrlPath, INTERNET_MAX_URL_LENGTH); 39 | if (!bRet) 40 | return FALSE; 41 | 42 | 43 | m_hCompleteEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL); // 创建事件句柄 44 | m_hCancelEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL); 45 | 46 | if (NULL == m_hCompleteEvent || NULL == m_hCancelEvent) 47 | { 48 | CloseRequest(); 49 | return FALSE; 50 | } 51 | 52 | if (m_strProxy.size() > 0) 53 | { 54 | dwAccessType = INTERNET_OPEN_TYPE_PROXY; 55 | lpszProxy = m_strProxy.c_str(); 56 | } 57 | else 58 | { 59 | dwAccessType = INTERNET_OPEN_TYPE_PRECONFIG; 60 | lpszProxy = NULL; 61 | } 62 | 63 | m_hInternet = ::InternetOpen(IE8_USER_AGENT, dwAccessType, lpszProxy, NULL, INTERNET_FLAG_ASYNC); 64 | if (NULL == m_hInternet) 65 | { 66 | CloseRequest(); 67 | return FALSE; 68 | } 69 | 70 | if (!m_strUser.empty()) // 设置代理用户名 71 | { 72 | ::InternetSetOptionEx(m_hInternet, INTERNET_OPTION_PROXY_USERNAME, (LPVOID)m_strUser.c_str(), m_strUser.size() + 1, 0); 73 | } 74 | 75 | if (!m_strPwd.empty()) // 设置代理密码 76 | { 77 | ::InternetSetOptionEx(m_hInternet, INTERNET_OPTION_PROXY_PASSWORD, (LPVOID)m_strPwd.c_str(), m_strPwd.size() + 1, 0); 78 | } 79 | 80 | // DWORDdwTimeOut; 81 | // DWORDdwSize = sizeof(dwTimeOut); 82 | // ::InternetQueryOption(m_hInternet,INTERNET_OPTION_CONNECT_TIMEOUT, (LPVOID)&dwTimeOut, &dwSize); 83 | 84 | INTERNET_STATUS_CALLBACKlpCallBackFunc; // 设置状态回调函数 85 | lpCallBackFunc = ::InternetSetStatusCallback(m_hInternet, (INTERNET_STATUS_CALLBACK)&StatusCallback); 86 | if (INTERNET_INVALID_STATUS_CALLBACK == lpCallBackFunc) 87 | { 88 | CloseRequest(); 89 | return FALSE; 90 | } 91 | 92 | m_dwContext = CONNECTED_EVENT; 93 | m_hConnect = ::InternetConnect(m_hInternet, szHostName, nPort, NULL, _T("HTTP/1.1"), INTERNET_SERVICE_HTTP, 0, (DWORD_PTR)this); 94 | if (NULL == m_hConnect) 95 | { 96 | if (::GetLastError() != ERROR_IO_PENDING) 97 | { 98 | CloseRequest(); 99 | return FALSE; 100 | } 101 | } 102 | 103 | bRet = WaitForEvent(CONNECTED_EVENT, m_dwConnectTimeOut); 104 | if (!bRet) 105 | { 106 | CloseRequest(); 107 | return FALSE; 108 | } 109 | 110 | TCHAR* lpMethod; 111 | if (nReqMethod == REQ_METHOD_GET) 112 | lpMethod = _T("GET"); 113 | else 114 | lpMethod = _T("POST"); 115 | 116 | DWORD dwFlags = INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE; 117 | if (INTERNET_DEFAULT_HTTPS_PORT == nPort) 118 | dwFlags |= INTERNET_FLAG_SECURE; 119 | 120 | m_dwContext = REQUEST_OPENED_EVENT; 121 | m_hRequest = ::HttpOpenRequest(m_hConnect, lpMethod, szUrlPath, _T("HTTP/1.1"), NULL, NULL, dwFlags, (DWORD_PTR)this); 122 | if (NULL == m_hRequest) 123 | { 124 | if (::GetLastError() != ERROR_IO_PENDING) 125 | { 126 | CloseRequest(); 127 | return FALSE; 128 | } 129 | } 130 | 131 | bRet = WaitForEvent(REQUEST_OPENED_EVENT, INFINITE); 132 | if (!bRet) 133 | { 134 | CloseRequest(); 135 | return FALSE; 136 | } 137 | 138 | return TRUE; 139 | } 140 | 141 | 142 | 143 | // 添加一个或多个HTTP请求头函数 144 | BOOL CHttpClient::AddReqHeaders(LPCTSTR lpHeaders) 145 | { 146 | if (NULL == m_hRequest || NULL == lpHeaders) 147 | return FALSE; 148 | 149 | return ::HttpAddRequestHeaders(m_hRequest, lpHeaders, _tcslen(lpHeaders), HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDREQ_FLAG_ADD); 150 | } 151 | 152 | // 发送HTTP请求函数 153 | BOOL CHttpClient::SendRequest(const CHAR * lpData, DWORD dwLen) 154 | { 155 | if (NULL == m_hRequest) 156 | return FALSE; 157 | 158 | BOOL bRet = ::HttpSendRequest(m_hRequest, NULL, 0, (LPVOID)lpData, dwLen); 159 | if (!bRet) 160 | { 161 | if (::GetLastError() != ERROR_IO_PENDING) 162 | return FALSE; 163 | } 164 | 165 | bRet = WaitForEvent(REQUEST_COMPLETE_EVENT, INFINITE); 166 | if (!bRet) 167 | return FALSE; 168 | 169 | return TRUE; 170 | } 171 | 172 | // 开始发送HTTP请求函数 173 | BOOL CHttpClient::SendRequestEx(DWORD dwLen) 174 | { 175 | if (NULL == m_hRequest) 176 | return FALSE; 177 | 178 | INTERNET_BUFFERS stInetBuf = { 0 }; 179 | stInetBuf.dwStructSize = sizeof(INTERNET_BUFFERS); 180 | stInetBuf.dwBufferTotal = dwLen; 181 | 182 | BOOL bRet = ::HttpSendRequestEx(m_hRequest, &stInetBuf, NULL, 0, (DWORD_PTR)this); 183 | if (!bRet) 184 | { 185 | if (::GetLastError() != ERROR_IO_PENDING) 186 | return FALSE; 187 | 188 | bRet = WaitForEvent(REQUEST_COMPLETE_EVENT, INFINITE); 189 | if (!bRet) 190 | return FALSE; 191 | } 192 | 193 | return TRUE; 194 | } 195 | 196 | // 发送HTTP请求消息体数据函数 197 | BOOL CHttpClient::SendReqBodyData(const CHAR * lpBuf, DWORD dwLen, DWORD& dwSendLen) 198 | { 199 | if (NULL == m_hRequest || NULL == lpBuf || dwLen <= 0) 200 | return FALSE; 201 | 202 | dwSendLen = 0; 203 | BOOL bRet = ::InternetWriteFile(m_hRequest, lpBuf, dwLen, &dwSendLen); 204 | if (!bRet) 205 | { 206 | if (::GetLastError() != ERROR_IO_PENDING) 207 | return FALSE; 208 | 209 | bRet = WaitForEvent(REQUEST_COMPLETE_EVENT, INFINITE); 210 | if (!bRet) 211 | return FALSE; 212 | } 213 | else 214 | { 215 | bRet = WaitForEvent(USER_CANCEL_EVENT, 0); 216 | if (!bRet) 217 | return FALSE; 218 | } 219 | 220 | return TRUE; 221 | } 222 | 223 | 224 | 225 | // 结束发送HTTP请求函数 226 | BOOL CHttpClient::EndSendRequest() 227 | { 228 | BOOL bRet; 229 | if (NULL == m_hRequest) 230 | return FALSE; 231 | 232 | bRet = ::HttpEndRequest(m_hRequest, NULL, HSR_INITIATE, (DWORD_PTR)this); 233 | if (!bRet) 234 | { 235 | if (::GetLastError() != ERROR_IO_PENDING) 236 | return FALSE; 237 | 238 | bRet = WaitForEvent(REQUEST_COMPLETE_EVENT, INFINITE); 239 | if (!bRet) 240 | return FALSE; 241 | } 242 | 243 | return TRUE; 244 | } 245 | 246 | // 获取HTTP响应码函数 247 | DWORD CHttpClient::GetRespCode() 248 | { 249 | DWORD dwRespCode = 0; 250 | DWORD dwSize = sizeof(dwRespCode); 251 | BOOL bRet = ::HttpQueryInfo(m_hRequest, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &dwRespCode, &dwSize, NULL); 252 | if (bRet) 253 | return dwRespCode; 254 | else 255 | return 0; 256 | } 257 | 258 | // 获取全部HTTP头 259 | tstring CHttpClient::GetRespHeader() 260 | { 261 | CHAR * lpRespHeader = NULL; 262 | DWORD dwRespHeaderLen = 0; 263 | tstring strRespHeader; 264 | BOOL bRet = ::HttpQueryInfo(m_hRequest, HTTP_QUERY_RAW_HEADERS_CRLF, (LPVOID)lpRespHeader, &dwRespHeaderLen, NULL); 265 | if (!bRet) 266 | { 267 | if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) 268 | { 269 | lpRespHeader = new CHAR[dwRespHeaderLen]; 270 | if (lpRespHeader != NULL) 271 | { 272 | memset(lpRespHeader, 0, dwRespHeaderLen); 273 | bRet = ::HttpQueryInfo(m_hRequest, HTTP_QUERY_RAW_HEADERS_CRLF, (LPVOID)lpRespHeader, &dwRespHeaderLen, NULL); 274 | if (bRet) 275 | { 276 | strRespHeader = (TCHAR *)lpRespHeader; 277 | } 278 | } 279 | } 280 | } 281 | 282 | if (lpRespHeader != NULL) 283 | { 284 | delete[]lpRespHeader; 285 | lpRespHeader = NULL; 286 | } 287 | 288 | return strRespHeader; 289 | } 290 | 291 | // 获取HTTP头指定字段名称的值 292 | tstring CHttpClient::GetRespHeader(LPCTSTR lpszName, int nIndex/* = 0*/) 293 | { 294 | if (NULL == lpszName) 295 | return _T(""); 296 | 297 | tstring strLine; 298 | int nNameLen, nIndex2 = 0; 299 | nNameLen = _tcslen(lpszName); 300 | if (nNameLen <= 0) 301 | return _T(""); 302 | 303 | if (m_arrRespHeader.size() <= 0) 304 | { 305 | if (!__GetRespHeader()) 306 | return _T(""); 307 | } 308 | 309 | 310 | for (int i = 0; i < (int)m_arrRespHeader.size(); i++) 311 | { 312 | strLine = m_arrRespHeader[i]; 313 | if (!_tcsnicmp(strLine.c_str(), lpszName, nNameLen)) 314 | { 315 | if (nIndex == nIndex2) 316 | { 317 | int nPos = nNameLen; 318 | int nLineLen = (int)strLine.size(); 319 | 320 | for (; nPos < nLineLen &&strLine[nPos] == _T(' '); ++nPos) 321 | ; // 跳过前导空格 322 | if (strLine[nPos] == _T(':')) // 跳过“:”符号 323 | nPos++; 324 | 325 | for (; nPos < nLineLen &&strLine[nPos] == _T(' '); ++nPos) 326 | ; // 跳过前导空格 327 | 328 | return strLine.substr(nPos); 329 | } 330 | 331 | nIndex2++; 332 | } 333 | } 334 | 335 | return _T(""); 336 | } 337 | 338 | // 获取HTTP头指定字段名称的值(Int) 339 | int CHttpClient::GetRespHeaderByInt(LPCTSTR lpszName, int nIndex/* = 0*/) 340 | { 341 | tstring strValue = GetRespHeader(lpszName, nIndex); 342 | return _tstoi(strValue.c_str()); 343 | } 344 | 345 | // 获取HTTP响应消息体数据函数 346 | BOOL CHttpClient::GetRespBodyData(CHAR * lpBuf, DWORD dwLen, DWORD& dwRecvLen) 347 | { 348 | if (NULL == m_hRequest || NULL == lpBuf || dwLen <= 0) 349 | return FALSE; 350 | 351 | INTERNET_BUFFERSA stInetBuf = { 0 }; 352 | BOOL bRet; 353 | dwRecvLen = 0; 354 | memset(lpBuf, 0, dwLen); 355 | 356 | stInetBuf.dwStructSize = sizeof(stInetBuf); 357 | stInetBuf.lpvBuffer = lpBuf; 358 | stInetBuf.dwBufferLength = dwLen; 359 | 360 | bRet = ::InternetReadFileExA(m_hRequest, &stInetBuf, 0, (DWORD_PTR)this); 361 | if (!bRet) 362 | { 363 | if (::GetLastError() != ERROR_IO_PENDING) 364 | return FALSE; 365 | 366 | bRet = WaitForEvent(REQUEST_COMPLETE_EVENT, INFINITE); 367 | if (!bRet) 368 | return FALSE; 369 | } 370 | else 371 | { 372 | bRet = WaitForEvent(USER_CANCEL_EVENT, 0); 373 | if (!bRet) 374 | return FALSE; 375 | } 376 | 377 | dwRecvLen = stInetBuf.dwBufferLength; 378 | 379 | return TRUE; 380 | } 381 | 382 | // 关闭HTTP请求函数 383 | void CHttpClient::CloseRequest() 384 | { 385 | if (m_hCompleteEvent != NULL) 386 | { 387 | ::CloseHandle(m_hCompleteEvent); 388 | m_hCompleteEvent = NULL; 389 | } 390 | 391 | if (m_hCancelEvent != NULL) 392 | { 393 | ::CloseHandle(m_hCancelEvent); 394 | m_hCancelEvent = NULL; 395 | } 396 | 397 | if (m_hRequest) 398 | { 399 | ::InternetCloseHandle(m_hRequest); 400 | m_hRequest = NULL; 401 | } 402 | 403 | if (m_hConnect) 404 | { 405 | ::InternetCloseHandle(m_hConnect); 406 | m_hConnect = NULL; 407 | } 408 | 409 | if (m_hInternet) 410 | { 411 | ::InternetCloseHandle(m_hInternet); 412 | m_hInternet = NULL; 413 | } 414 | 415 | 416 | m_arrRespHeader.clear(); 417 | 418 | m_dwContext = 0; 419 | m_strProxy = _T(""); 420 | m_strUser = _T(""); 421 | m_strPwd = _T(""); 422 | } 423 | 424 | // 设置连接超时(单位:毫秒) 425 | void CHttpClient::SetConnectTimeOut(DWORD dwTimeOut) 426 | { 427 | m_dwConnectTimeOut = dwTimeOut; 428 | } 429 | 430 | // 设置取消事件函数 431 | void CHttpClient::SetCancalEvent() 432 | { 433 | if (m_hCancelEvent != NULL) 434 | ::SetEvent(m_hCancelEvent); 435 | } 436 | 437 | // 设置HTTP代理服务器 438 | void CHttpClient::SetProxy(LPCTSTR lpszServer, WORD nPort, LPCTSTR lpszUser/* = NULL*/, LPCTSTR lpszPwd/* = NULL*/) 439 | { 440 | if (NULL == lpszServer) 441 | return; 442 | 443 | TCHAR szProxy[INTERNET_MAX_URL_LENGTH] = { 0 }; 444 | wsprintf(szProxy, _T("%s:%d"), lpszServer, nPort); 445 | m_strProxy = szProxy; 446 | if (lpszUser != NULL) 447 | m_strUser = lpszUser; 448 | 449 | if (lpszPwd != NULL) 450 | m_strPwd = lpszPwd; 451 | } 452 | 453 | // 状态回调函数 454 | void CHttpClient::StatusCallback(HINTERNET hInternet, DWORD dwContext, DWORD dwInternetStatus, LPVOID lpStatusInfo, DWORD dwStatusInfoLen) 455 | { 456 | CHttpClient * lpThis = (CHttpClient *)dwContext; 457 | if (NULL == lpThis) 458 | return; 459 | 460 | switch (dwInternetStatus) 461 | { 462 | case INTERNET_STATUS_HANDLE_CREATED: 463 | { 464 | 465 | if (CONNECTED_EVENT == lpThis->m_dwContext) 466 | 467 | { 468 | 469 | INTERNET_ASYNC_RESULT * lpRes = (INTERNET_ASYNC_RESULT *)lpStatusInfo; 470 | 471 | lpThis->m_hConnect = (HINTERNET)lpRes->dwResult; 472 | 473 | ::SetEvent(lpThis->m_hCompleteEvent); 474 | 475 | } 476 | else if (REQUEST_OPENED_EVENT == lpThis->m_dwContext) 477 | { 478 | INTERNET_ASYNC_RESULT * lpRes = (INTERNET_ASYNC_RESULT *)lpStatusInfo; 479 | lpThis->m_hRequest = (HINTERNET)lpRes->dwResult; 480 | ::SetEvent(lpThis->m_hCompleteEvent); 481 | } 482 | } 483 | 484 | break; 485 | 486 | case INTERNET_STATUS_REQUEST_SENT: 487 | { 488 | DWORD * lpBytesSent = (DWORD *)lpStatusInfo; 489 | } 490 | 491 | break; 492 | 493 | case INTERNET_STATUS_REQUEST_COMPLETE: 494 | { 495 | 496 | INTERNET_ASYNC_RESULT * lpRes = (INTERNET_ASYNC_RESULT *)lpStatusInfo; 497 | ::SetEvent(lpThis->m_hCompleteEvent); 498 | } 499 | 500 | break; 501 | 502 | case INTERNET_STATUS_RECEIVING_RESPONSE: 503 | { 504 | 505 | } 506 | break; 507 | 508 | case INTERNET_STATUS_RESPONSE_RECEIVED: 509 | { 510 | DWORD * dwBytesReceived = (DWORD *)lpStatusInfo; 511 | } 512 | break; 513 | } 514 | } 515 | 516 | // 解析Url函数(协议,主机名,端口,文件路径) 517 | BOOL CHttpClient::ParseURL(LPCTSTR lpszUrl, LPTSTR lpszScheme, DWORD dwSchemeLength, 518 | LPTSTR lpszHostName, DWORD dwHostNameLength, WORD& nPort, 519 | LPTSTR lpszUrlPath, DWORD dwUrlPathLength) 520 | { 521 | URL_COMPONENTS stUrlComponents = { 0 }; 522 | stUrlComponents.dwStructSize = sizeof(URL_COMPONENTS); 523 | stUrlComponents.lpszScheme = lpszScheme; 524 | stUrlComponents.dwSchemeLength = dwSchemeLength; 525 | stUrlComponents.lpszHostName = lpszHostName; 526 | stUrlComponents.dwHostNameLength = dwHostNameLength; 527 | stUrlComponents.lpszUrlPath = lpszUrlPath; 528 | stUrlComponents.dwUrlPathLength = dwUrlPathLength; 529 | 530 | BOOL bRet = ::InternetCrackUrl(lpszUrl, 0, 0, &stUrlComponents); 531 | if (bRet) 532 | { 533 | nPort = stUrlComponents.nPort; 534 | } 535 | 536 | return bRet; 537 | } 538 | 539 | 540 | 541 | // 等待事件函数 542 | 543 | BOOL CHttpClient::WaitForEvent(HTTP_STATUS_EVENT nEvent, DWORD dwTimeOut) 544 | { 545 | HANDLE hEvent[2] = { 0 }; 546 | int nCount = 0; 547 | switch (nEvent) 548 | { 549 | case CONNECTED_EVENT: 550 | case REQUEST_OPENED_EVENT: 551 | case REQUEST_COMPLETE_EVENT: 552 | { 553 | hEvent[0] = m_hCancelEvent; 554 | hEvent[1] = m_hCompleteEvent; 555 | nCount = 2; 556 | } 557 | break; 558 | 559 | 560 | case USER_CANCEL_EVENT: 561 | { 562 | hEvent[0] = m_hCancelEvent; 563 | nCount = 1; 564 | } 565 | break; 566 | 567 | 568 | default: 569 | return FALSE; 570 | } 571 | 572 | if (1 == nCount) 573 | { 574 | DWORD dwRet = ::WaitForSingleObject(hEvent[0], dwTimeOut); 575 | if (WAIT_OBJECT_0 == dwRet) 576 | return FALSE; 577 | else 578 | return TRUE; 579 | } 580 | else 581 | { 582 | DWORD dwRet = ::WaitForMultipleObjects(2, hEvent, FALSE, dwTimeOut); 583 | if (dwRet != WAIT_OBJECT_0 + 1) 584 | return FALSE; 585 | else 586 | return TRUE; 587 | } 588 | } 589 | 590 | 591 | 592 | // 获取HTTP响应头长度 593 | DWORD CHttpClient::__GetRespHeaderLen() 594 | { 595 | BOOL bRet; 596 | LPVOID lpBuffer = NULL; 597 | DWORD dwBufferLength = 0; 598 | bRet = ::HttpQueryInfo(m_hRequest, HTTP_QUERY_RAW_HEADERS_CRLF, lpBuffer, &dwBufferLength, NULL); 599 | if (!bRet) 600 | { 601 | if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) 602 | { 603 | return dwBufferLength; 604 | } 605 | } 606 | 607 | return 0; 608 | } 609 | 610 | // 获取HTTP响应头,按行保存在m_arrRespHeader数组 611 | BOOL CHttpClient::__GetRespHeader() 612 | { 613 | CHAR * lpRespHeader; 614 | DWORD dwRespHeaderLen; 615 | m_arrRespHeader.clear(); 616 | 617 | dwRespHeaderLen = __GetRespHeaderLen(); 618 | if (dwRespHeaderLen <= 0) 619 | return FALSE; 620 | 621 | lpRespHeader = new CHAR[dwRespHeaderLen]; 622 | if (NULL == lpRespHeader) 623 | return FALSE; 624 | 625 | memset(lpRespHeader, 0, dwRespHeaderLen); 626 | 627 | BOOL bRet = ::HttpQueryInfo(m_hRequest, HTTP_QUERY_RAW_HEADERS_CRLF, (LPVOID)lpRespHeader, &dwRespHeaderLen, NULL); 628 | if (!bRet) 629 | { 630 | delete[]lpRespHeader; 631 | lpRespHeader = NULL; 632 | return FALSE; 633 | } 634 | 635 | tstring strHeader = (TCHAR *)lpRespHeader; 636 | tstring strLine; 637 | int nStart = 0; 638 | tstring::size_type nPos = strHeader.find(_T("\r\n"), nStart); 639 | while (nPos != tstring::npos) 640 | { 641 | strLine = strHeader.substr(nStart, nPos - nStart); 642 | if (strLine != _T("")) 643 | m_arrRespHeader.push_back(strLine); 644 | 645 | nStart = nPos + 2; 646 | nPos = strHeader.find(_T("\r\n"), nStart); 647 | } 648 | 649 | delete[]lpRespHeader; 650 | lpRespHeader = NULL; 651 | return TRUE; 652 | } 653 | -------------------------------------------------------------------------------- /HttpClient.h: -------------------------------------------------------------------------------- 1 | /** 2 | * WinInet封装类,可用于windows上http请求, HttpClient.h 3 | * zhangyl 2016.07.15 mail: balloonwj@qq.com 4 | */ 5 | 6 | #ifndef __HTTP_CLIENT_H__ 7 | #define __HTTP_CLIENT_H__ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #pragma comment(lib, "wininet.lib") 14 | 15 | 16 | #if defined(UNICODE) || defined(_UNICODE) 17 | typedef std::wstring tstring; 18 | #else 19 | typedef std::string tstring; 20 | #endif 21 | 22 | // IE8 on Windows 7 23 | #define IE8_USER_AGENT _T("Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1;Trident/4.0)") 24 | 25 | // HTTP请求方法 26 | enum HTTP_REQ_METHOD 27 | { 28 | REQ_METHOD_GET, 29 | REQ_METHOD_POST, 30 | }; 31 | 32 | // HTTP状态事件标识 33 | enum HTTP_STATUS_EVENT 34 | { 35 | CONNECTED_EVENT, 36 | REQUEST_OPENED_EVENT, 37 | REQUEST_COMPLETE_EVENT, 38 | USER_CANCEL_EVENT 39 | }; 40 | 41 | // WinInet Http异步封装类 42 | class CHttpClient 43 | { 44 | public: 45 | CHttpClient(void); 46 | ~CHttpClient(void); 47 | 48 | public: 49 | BOOL OpenRequest(LPCTSTR lpszUrl, HTTP_REQ_METHOD nReqMethod = REQ_METHOD_GET); // 打开HTTP请求函数 50 | BOOL AddReqHeaders(LPCTSTR lpHeaders); // 添加一个或多个HTTP请求头函数 51 | BOOL SendRequest(const CHAR* lpData, DWORD dwLen); // 发送HTTP请求函数 52 | BOOL SendRequestEx(DWORD dwLen); // 开始发送HTTP请求函数 53 | BOOL SendReqBodyData(const CHAR* lpBuf, DWORD dwLen, DWORD& dwSendLen); // 发送HTTP请求消息体数据函数 54 | BOOL EndSendRequest(); // 结束发送HTTP请求函数 55 | DWORD GetRespCode(); // 获取HTTP响应码函数 56 | tstring GetRespHeader(); // 获取全部HTTP头 57 | tstring GetRespHeader(LPCTSTR lpszName, int nIndex = 0); // 获取HTTP头指定字段名称的值 58 | int GetRespHeaderByInt(LPCTSTR lpszName, int nIndex = 0); // 获取HTTP头指定字段名称的值(Int) 59 | BOOL GetRespBodyData(CHAR * lpBuf, DWORD dwLen, DWORD& dwRecvLen); // 获取HTTP响应消息体数据函数 60 | void CloseRequest(); // 关闭HTTP请求函数 61 | void SetConnectTimeOut(DWORD dwTimeOut); // 设置连接超时(单位:毫秒) 62 | void SetCancalEvent(); // 设置取消事件函数 63 | void SetProxy(LPCTSTR lpszServer, WORD nPort, LPCTSTR lpszUser = NULL, LPCTSTR lpszPwd = NULL);// 设置HTTP代理服务器 64 | 65 | private: 66 | // 状态回调函数 67 | static void __stdcall StatusCallback(HINTERNET hInternet, DWORD dwContext, DWORD dwInternetStatus, LPVOIDlpStatusInfo, DWORD dwStatusInfoLen); 68 | // 解析Url函数(协议,主机名,端口,文件路径) 69 | BOOL ParseURL(LPCTSTR lpszUrl, LPTSTR lpszScheme, DWORD dwSchemeLength, LPTSTR lpszHostName, DWORD dwHostNameLength, WORD& nPort, LPTSTR lpszUrlPath, DWORD dwUrlPathLength); 70 | // 等待事件函数 71 | BOOL WaitForEvent(HTTP_STATUS_EVENT nEvent, DWORD dwTimeOut); 72 | // 获取HTTP响应头长度 73 | DWORD __GetRespHeaderLen(); 74 | // 获取HTTP响应头,按行保存在m_arrRespHeader数组 75 | BOOL __GetRespHeader(); 76 | 77 | private: 78 | HINTERNET m_hInternet; // 会话句柄 79 | HINTERNET m_hConnect; // 连接句柄 80 | HINTERNET m_hRequest; // 请求句柄 81 | 82 | HANDLE m_hCompleteEvent; // 操作完成事件句柄 83 | HANDLE m_hCancelEvent; // 外部取消事件句柄 84 | 85 | DWORD m_dwConnectTimeOut; // 连接超时时间 86 | DWORD m_dwContext; // 当前操作上下文 87 | 88 | std::vector m_arrRespHeader; // Http响应头数组 89 | 90 | tstring m_strProxy; // 代理服务器(主机名:端口) 91 | tstring m_strUser, m_strPwd; // 代理服务器的用户名和密码 92 | }; 93 | 94 | #endif //!__HTTP_CLIENT_H__ 95 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 强大的Http请求类,封装了windows WinInet底层API 2 | 3 | 如有任何技术问题,欢迎联系QQ: 906106643 4 | 5 | 关于WinInet的详细教程:http://blog.csdn.net/analogous_love/article/details/72515002 6 | 7 | 我的csdn博客:http://blog.csdn.net/analogous_love 8 | --------------------------------------------------------------------------------