CHttpClient
用于表示一个基于 C++ 的 HTTP 客户端,它内部使用了 libcurl
来实现 HTTP 请求的发送和接收。libcurl
是一个强大的库,支持多种协议,包括 HTTP、HTTPS、FTP 等,并且提供了丰富的 API 来定制请求。
该类封装了 libcurl
的基本功能,用于发送 GET 和 POST 请求。请注意,这个假设你已经有了 libcurl
的开发环境配置好,并且你的项目能够链接到 libcurl
。
#ifndef __HTTP_CURL_H__
#define __HTTP_CURL_H__
#include <string>
#include "curl.h"
class CHttpClient
{
public:
CHttpClient(void);
~CHttpClient(void);
public:
/**
* @brief HTTP POST请求
* @param strUrl 输入参数,请求的Url地址,如:http://www.baidu.com
* @param strPost 输入参数,使用如下格式para1=val1?2=val2&…
* @param strResponse 输出参数,返回的内容
* @return 返回是否Post成功
*/
int Post(const std::string & strUrl, const std::string & strPost, std::string & strResponse, bool bSaveCook = false);
/**
* @brief HTTP GET请求
* @param strUrl 输入参数,请求的Url地址,如:http://www.baidu.com
* @param strResponse 输出参数,返回的内容
* @return 返回是否Post成功
*/
int Get(const std::string & strUrl, std::string & strResponse);
/**
* @brief HTTPS POST请求,无证书版本
* @param strUrl 输入参数,请求的Url地址,如:https://www.alipay.com
* @param strPost 输入参数,使用如下格式para1=val1?2=val2&…
* @param strResponse 输出参数,返回的内容
* @param pCaPath 输入参数,为CA证书的路径.如果输入为NULL,则不验证服务器端证书的有效性.
* @return 返回是否Post成功
*/
int Posts(const std::string & strUrl, const std::string & strPost, std::string & strResponse, const char * pCaPath = NULL);
/**
* @brief HTTPS GET请求,无证书版本
* @param strUrl 输入参数,请求的Url地址,如:https://www.alipay.com
* @param strResponse 输出参数,返回的内容
* @param pCaPath 输入参数,为CA证书的路径.如果输入为NULL,则不验证服务器端证书的有效性.
* @return 返回是否Post成功
*/
int Gets(const std::string & strUrl, std::string & strResponse, const char * pCaPath = NULL);
int Put(const std::string& strUrl, const std::string& strPut, std::string &strResponse);
public:
void SetDebug(bool bDebug);
private:
bool m_bDebug;
};
#endif
#include "HttpClient.h"
#include "curl/curl.h"
#include <string>
#include "curl//easy.h"
CHttpClient::CHttpClient(void) :
m_bDebug(false)
{
}
CHttpClient::~CHttpClient(void)
{
}
static int OnDebug(CURL *, curl_infotype itype, char * pData, size_t size, void *)
{
if(itype == CURLINFO_TEXT)
{
//printf("[TEXT]%s\n", pData);
}
else if(itype == CURLINFO_HEADER_IN)
{
printf("[HEADER_IN]%s\n", pData);
}
else if(itype == CURLINFO_HEADER_OUT)
{
printf("[HEADER_OUT]%s\n", pData);
}
else if(itype == CURLINFO_DATA_IN)
{
printf("[DATA_IN]%s\n", pData);
}
else if(itype == CURLINFO_DATA_OUT)
{
printf("[DATA_OUT]%s\n", pData);
}
return 0;
}
static size_t OnWriteData(void* buffer, size_t size, size_t nmemb, void* lpVoid)
{
std::string* str = (std::string*)lpVoid;
if( NULL == str || NULL == buffer )
{
return -1;
}
char* pData = (char*)buffer;
str->append(pData, size * nmemb);
return nmemb;
}
int CHttpClient::Post(const std::string & strUrl, const std::string & strPost, std::string & strResponse, bool bSaveCook)
{
CURLcode res;
CURL* curl = curl_easy_init();
if(NULL == curl)
{
return CURLE_FAILED_INIT;
}
if(m_bDebug)
{
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug);
}
curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, strPost.c_str());
curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
//curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10);
curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "cookies.txt");
struct curl_slist *slist = NULL;
slist = curl_slist_append(slist, "Expect:"); //防止Expect:100-Continue
slist = curl_slist_append(slist, "Content-Type:application/json");
slist = curl_slist_append(slist, "charset:utf-8");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist); //set head
if ( bSaveCook )
{
curl_easy_setopt(curl, CURLOPT_COOKIEJAR, "cookies.txt");
}
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
return res;
}
int CHttpClient::Get(const std::string & strUrl, std::string & strResponse)
{
CURLcode res;
CURL* curl = curl_easy_init();
if(NULL == curl)
{
return CURLE_FAILED_INIT;
}
if(m_bDebug)
{
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug);
}
std::string strUrlTmp ;
#ifdef _LINUX_
std::string strParam;
std::string::size_type nPos = strUrl.find("?");
if ( nPos != std::string::npos )
{
strParam = strUrl.substr(strUrl.find("?")+1);
char * escape_control = curl_escape(strParam.c_str(), strParam.size());
strParam = escape_control;
curl_free(escape_control);
strUrlTmp = strUrl.substr(0, strUrl.find("?")+1) + strParam;
}
else
{
strUrlTmp = strUrl;
}
#else
strUrlTmp = strUrl;
#endif
curl_easy_setopt(curl, CURLOPT_URL, strUrlTmp.c_str());
curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);
/**
* 当多个线程都使用超时处理的时候,同时主线程中有sleep或是wait等操作。
* 如果不设置这个选项,libcurl将会发信号打断这个wait从而导致程序退出。
*/
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
//curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10);
curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, 1); //这个很重要,curl 有个重用机制,访问的链接不会立即释放,如果访问过于平凡的可能会导致服务器端口被沾满,无法访问的情况(CURLE_COULDNT_CONNECT /* 7 */ 这个是返回的错误码)
curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "E:\\cookies.txt");
struct curl_slist *slist = NULL;
slist = curl_slist_append(slist, "Accept:application/json");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist); //set head
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
return res;
}
int CHttpClient::Posts(const std::string & strUrl, const std::string & strPost, std::string & strResponse, const char * pCaPath)
{
CURLcode res;
CURL* curl = curl_easy_init();
if(NULL == curl)
{
return CURLE_FAILED_INIT;
}
if(m_bDebug)
{
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug);
}
curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, strPost.c_str());
curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
if(NULL == pCaPath)
{
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
}
else
{
//缺省情况就是PEM,所以无需设置,另外支持DER
//curl_easy_setopt(curl,CURLOPT_SSLCERTTYPE,"PEM");
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true);
curl_easy_setopt(curl, CURLOPT_CAINFO, pCaPath);
}
//curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
return res;
}
int CHttpClient::Gets(const std::string & strUrl, std::string & strResponse, const char * pCaPath)
{
CURLcode res;
CURL* curl = curl_easy_init();
if(NULL == curl)
{
return CURLE_FAILED_INIT;
}
if(m_bDebug)
{
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug);
}
curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());
curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
if(NULL == pCaPath)
{
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
}
else
{
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true);
curl_easy_setopt(curl, CURLOPT_CAINFO, pCaPath);
}
//curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10);
curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, 1); //这个很重要,curl 有个重用机制,访问的链接不会立即释放,如果访问过于平凡的可能会导致服务器端口被沾满,无法访问的情况(CURLE_COULDNT_CONNECT /* 7 */ 这个是返回的错误码)
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
return res;
}
int CHttpClient::Put(const std::string& strUrl, const std::string& strPut, std::string &strResponse)
{
CURLcode res;
CURL* curl = curl_easy_init();
if (NULL == curl)
{
return CURLE_FAILED_INIT;
}
if (m_bDebug)
{
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug);
}
curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, strPut.c_str());
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, strPut.length());
struct curl_slist *slist = NULL;
slist = curl_slist_append(slist, "Content-Type: XXXX");
slist = curl_slist_append(slist, "Accept:XXXX");
slist = curl_slist_append(slist, "XXXX");
slist = curl_slist_append(slist, "Expect:"); //防止Expect:100-Continue
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist); //set head
curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
//curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
return res;
}
///
void CHttpClient::SetDebug(bool bDebug)
{
m_bDebug = bDebug;
}