当使用C++做HTTP客户端时,目前通用的做法就是使用libcurl。其官方网站的地址是http://curl.haxx.se/,该网站主要提供了Curl和libcurl。Curl是命令行工具,用于完成FTP, FTPS, HTTP, HTTPS, GOPHER, TELNET, DICT, FILE 以及 LDAP的命令的请求及接收回馈。libcurl提供给开发者,用于使用C++跨平台的开发各种网络协议的请求及响应。里面的文档非常齐全,不过都是英文的。

    本文提供最简单的demo使用libcurl开发HttpClient。主要包括同步的HTTP GET、HTTP POST、HTTPS GET、HTTPS POST。

    下载libcurl包,如果使用Linux平台,建议下载源文件编译;如果使用Windows平台,建议下载Win32 - MSVC,下载地址是:http://curl.haxx.se/download.html

 

[cpp]  view plain copy
 
  1. #ifndef __HTTP_CURL_H__  
  2. #define __HTTP_CURL_H__  
  3.   
  4. #include <string>  
  5.   
  6. class CHttpClient  
  7. {  
  8. public:  
  9.     CHttpClient(void);  
  10.     ~CHttpClient(void);  
  11.   
  12. public:  
  13.     /** 
  14.     * @brief HTTP POST请求 
  15.     * @param strUrl 输入参数,请求的Url地址,如:http://www.baidu.com 
  16.     * @param strPost 输入参数,使用如下格式para1=val1¶2=val2&… 
  17.     * @param strResponse 输出参数,返回的内容 
  18.     * @return 返回是否Post成功 
  19.     */  
  20.     int Post(const std::string & strUrl, const std::string & strPost, std::string & strResponse);  
  21.   
  22.     /** 
  23.     * @brief HTTP GET请求 
  24.     * @param strUrl 输入参数,请求的Url地址,如:http://www.baidu.com 
  25.     * @param strResponse 输出参数,返回的内容 
  26.     * @return 返回是否Post成功 
  27.     */  
  28.     int Get(const std::string & strUrl, std::string & strResponse);  
  29.   
  30.     /** 
  31.     * @brief HTTPS POST请求,无证书版本 
  32.     * @param strUrl 输入参数,请求的Url地址,如:https://www.alipay.com 
  33.     * @param strPost 输入参数,使用如下格式para1=val1¶2=val2&… 
  34.     * @param strResponse 输出参数,返回的内容 
  35.     * @param pCaPath 输入参数,为CA证书的路径.如果输入为NULL,则不验证服务器端证书的有效性. 
  36.     * @return 返回是否Post成功 
  37.     */  
  38.     int Posts(const std::string & strUrl, const std::string & strPost, std::string & strResponse, const char * pCaPath = NULL);  
  39.   
  40.     /** 
  41.     * @brief HTTPS GET请求,无证书版本 
  42.     * @param strUrl 输入参数,请求的Url地址,如:https://www.alipay.com 
  43.     * @param strResponse 输出参数,返回的内容 
  44.     * @param pCaPath 输入参数,为CA证书的路径.如果输入为NULL,则不验证服务器端证书的有效性. 
  45.     * @return 返回是否Post成功 
  46.     */  
  47.     int Gets(const std::string & strUrl, std::string & strResponse, const char * pCaPath = NULL);  
  48.   
  49. public:  
  50.     void SetDebug(bool bDebug);  
  51.   
  52. private:  
  53.     bool m_bDebug;  
  54. };  
  55.   
  56. #endif  

[cpp]  view plain copy
 
  1. #include "httpclient.h"  
  2. #include "curl/curl.h"  
  3. #include <string>  
  4.   
  5. CHttpClient::CHttpClient(void) :   
  6. m_bDebug(false)  
  7. {  
  8.   
  9. }  
  10.   
  11. CHttpClient::~CHttpClient(void)  
  12. {  
  13.   
  14. }  
  15.   
  16. static int OnDebug(CURL *, curl_infotype itype, char * pData, size_t size, void *)  
  17. {  
  18.     if(itype == CURLINFO_TEXT)  
  19.     {  
  20.         //printf("[TEXT]%s\n", pData);  
  21.     }  
  22.     else if(itype == CURLINFO_HEADER_IN)  
  23.     {  
  24.         printf("[HEADER_IN]%s\n", pData);  
  25.     }  
  26.     else if(itype == CURLINFO_HEADER_OUT)  
  27.     {  
  28.         printf("[HEADER_OUT]%s\n", pData);  
  29.     }  
  30.     else if(itype == CURLINFO_DATA_IN)  
  31.     {  
  32.         printf("[DATA_IN]%s\n", pData);  
  33.     }  
  34.     else if(itype == CURLINFO_DATA_OUT)  
  35.     {  
  36.         printf("[DATA_OUT]%s\n", pData);  
  37.     }  
  38.     return 0;  
  39. }  
  40.   
  41. static size_t OnWriteData(void* buffer, size_t size, size_t nmemb, void* lpVoid)  
  42. {  
  43.     std::string* str = dynamic_cast<std::string*>((std::string *)lpVoid);  
  44.     if( NULL == str || NULL == buffer )  
  45.     {  
  46.         return -1;  
  47.     }  
  48.   
  49.     char* pData = (char*)buffer;  
  50.     str->append(pData, size * nmemb);  
  51.     return nmemb;  
  52. }  
  53.   
  54. int CHttpClient::Post(const std::string & strUrl, const std::string & strPost, std::string & strResponse)  
  55. {  
  56.     CURLcode res;  
  57.     CURL* curl = curl_easy_init();  
  58.     if(NULL == curl)  
  59.     {  
  60.         return CURLE_FAILED_INIT;  
  61.     }  
  62.     if(m_bDebug)  
  63.     {  
  64.         curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);  
  65.         curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug);  
  66.     }  
  67.     curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());  
  68.     curl_easy_setopt(curl, CURLOPT_POST, 1);  
  69.     curl_easy_setopt(curl, CURLOPT_POSTFIELDS, strPost.c_str());  
  70.     curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);  
  71.     curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);  
  72.     curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);  
  73.     curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);  
  74.     curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);  
  75.     curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);  
  76.     res = curl_easy_perform(curl);  
  77.     curl_easy_cleanup(curl);  
  78.     return res;  
  79. }  
  80.   
  81. int CHttpClient::Get(const std::string & strUrl, std::string & strResponse)  
  82. {  
  83.     CURLcode res;  
  84.     CURL* curl = curl_easy_init();  
  85.     if(NULL == curl)  
  86.     {  
  87.         return CURLE_FAILED_INIT;  
  88.     }  
  89.     if(m_bDebug)  
  90.     {  
  91.         curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);  
  92.         curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug);  
  93.     }  
  94. <pre name="code" class="cpp">   curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());  
  95.     curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);  
  96.     curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);  
  97.     curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);  
  98.     /** 
  99.     * 当多个线程都使用超时处理的时候,同时主线程中有sleep或是wait等操作。 
  100.     * 如果不设置这个选项,libcurl将会发信号打断这个wait从而导致程序退出。 
  101.     */  
  102.     curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);  
  103.     curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);  
  104.     curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);  
  105.     res = curl_easy_perform(curl);  
  106.     curl_easy_cleanup(curl);  
  107.     return res;  
  108. }  
  109.   
  110. int CHttpClient::Posts(const std::string & strUrl, const std::string & strPost, std::string & strResponse, const char * pCaPath)  
  111. {  
  112.     CURLcode res;  
  113.     CURL* curl = curl_easy_init();  
  114.     if(NULL == curl)  
  115.     {  
  116.         return CURLE_FAILED_INIT;  
  117.     }  
  118.     if(m_bDebug)  
  119.     {  
  120.         curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);  
  121.         curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug);  
  122.     }  
  123.     curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());  
  124.     curl_easy_setopt(curl, CURLOPT_POST, 1);  
  125.     curl_easy_setopt(curl, CURLOPT_POSTFIELDS, strPost.c_str());  
  126.     curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);  
  127.     curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);  
  128.     curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);  
  129.     curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);  
  130.     if(NULL == pCaPath)  
  131.     {  
  132.         curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);  
  133.         curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);  
  134.     }  
  135.     else  
  136.     {  
  137.         //缺省情况就是PEM,所以无需设置,另外支持DER  
  138.         //curl_easy_setopt(curl,CURLOPT_SSLCERTTYPE,"PEM");  
  139.         curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true);  
  140.         curl_easy_setopt(curl, CURLOPT_CAINFO, pCaPath);  
  141.     }  
  142.     curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);  
  143.     curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);  
  144.     res = curl_easy_perform(curl);  
  145.     curl_easy_cleanup(curl);  
  146.     return res;  
  147. }  
  148.   
  149. int CHttpClient::Gets(const std::string & strUrl, std::string & strResponse, const char * pCaPath)  
  150. {  
  151.     CURLcode res;  
  152.     CURL* curl = curl_easy_init();  
  153.     if(NULL == curl)  
  154.     {  
  155.         return CURLE_FAILED_INIT;  
  156.     }  
  157.     if(m_bDebug)  
  158.     {  
  159.         curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);  
  160.         curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug);  
  161.     }  
  162.     curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());  
  163.     curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);  
  164.     curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);  
  165.     curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);  
  166.     curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);  
  167.     if(NULL == pCaPath)  
  168.     {  
  169.         curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);  
  170.         curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);  
  171.     }  
  172.     else  
  173.     {  
  174.         curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true);  
  175.         curl_easy_setopt(curl, CURLOPT_CAINFO, pCaPath);  
  176.     }  
  177.     curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);  
  178.     curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);  
  179.     res = curl_easy_perform(curl);  
  180.     curl_easy_cleanup(curl);  
  181.     return res;  
  182. }  
  183.   
  184. ///  
  185.   
  186. void CHttpClient::SetDebug(bool bDebug)  
  187. {  
  188.     m_bDebug = bDebug;