本文主要通过代码示例,详细介绍一下CURL下载文件、上传文件、请求数据的使用
无论哪个操作都需要先初始化CURL:
CURLcode res = curl_global_init(CURL_GLOBAL_ALL);
if(CURLE_OK != res)
{
qDebug() << "lib curl is failed";
return ;
}
- 下载文件:
size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream) {
if (ptr == nullptr)
{
qDebug() << "write_data is erro";
return 0;
}
size_t written = fwrite(ptr, size, nmemb, stream);
return written;
}
//进度条
int progress_func(void* ptr, double totalToDownload, double nowDownloaded,
double totalToUpload, double nowUploaded)
{
qDebug() << "curSize" << nowDownloaded << "totalSize" << totalToDownload;
return 0;
}
//断点续传
long GetLocalFileLenth(const char* fileName)
{
FILE* fp = fopen(fileName, "r");
if (fp == nullptr)
{
return 0;
}
fseek(fp, 0, SEEK_END);
size_t size = ftell(fp);
fclose(fp);
return size; //单位是:byte
}
bool MyCurl::getFileFromURL(const QString &strUrl, const QString &strFilePath)
{
qDebug() << strUrl << strFilePath;
int bRet = false;
QEventLoop loop;
std::thread([&](){
CURLcode res;
/* 调用curl_easy_init()函数得到 easy interface型指针 */
qDebug() << "curl_easy_init";
m_pCurl = curl_easy_init();
if (!m_pCurl)
{
qDebug() << "m_pCurl is erro";
return false;
}
do
{
try {
qDebug() << "fopen";
m_fp = fopen(strFilePath.toUtf8().data(), "wb");
/* 调用curl_easy_setopt()设置传输选项 */
qDebug() << "CURLOPT_URL";
res = curl_easy_setopt(m_pCurl, CURLOPT_URL, strUrl.toUtf8().data());
if (res != CURLE_OK)
{
qDebug() << "CURLOPT_URL is erro";
fclose(m_fp);
curl_easy_cleanup(m_pCurl);
return false;
}
qDebug() << "CURLOPT_WRITEFUNCTION";
/* 根据curl_easy_setopt()设置的传输选项,实现回调函数以完成用户特定任务 */
res = curl_easy_setopt(m_pCurl, CURLOPT_WRITEFUNCTION, write_data);
if (res != CURLE_OK)
{
qDebug() << "CURLOPT_WRITEFUNCTION is erro";
break;
}
qDebug() << "CURLOPT_WRITEDATA";
/* 根据curl_easy_setopt()设置的传输选项,实现回调函数以完成用户特定任务 */
res = curl_easy_setopt(m_pCurl, CURLOPT_WRITEDATA, m_fp);
if (res != CURLE_OK)
{
qDebug() << "CURLOPT_WRITEDATA is erro";
break;
}
qDebug() << "CURLOPT_RESUME_FROM_LARGE";
res = curl_easy_setopt(m_pCurl, CURLOPT_RESUME_FROM_LARGE,GetLocalFileLenth(strFilePath.toUtf8().data()));
if (res != CURLE_OK)
{
qDebug() << "CURLOPT_RESUME_FROM_LARGE is erro";
break;
}
qDebug() << "CURLOPT_NOPROGRESS";
res = curl_easy_setopt(m_pCurl, CURLOPT_NOPROGRESS, false);
if (res != CURLE_OK)
{
qDebug() << "CURLOPT_NOPROGRESS is erro";
break;
}
qDebug() << "CURLOPT_PROGRESSFUNCTION";
res = curl_easy_setopt(m_pCurl, CURLOPT_PROGRESSFUNCTION, progress_func);
if (res != CURLE_OK)
{
qDebug() << "CURLOPT_PROGRESSFUNCTION is erro";
break;
}
qDebug() << "curl_easy_perform";
if(curl_easy_perform(m_pCurl) != CURLE_OK)
{
qDebug() << "curl break";
break;
}
} catch (...) {
}
qDebug() << "curl finish";
bRet = true;
} while (false);
fclose(m_fp);
curl_easy_cleanup(m_pCurl);
}).detach();
loop.exec();
return true;
}
- 上传和数据请求共用函数:
struct MemoryStruct
{
char *memory;
size_t size;
MemoryStruct()
{
memory = (char *)malloc(1);
size = 0;
}
~MemoryStruct()
{
free(memory);
memory = nullptr;
size = 0;
}
};
size_t WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data)
{
size_t realsize = size * nmemb;
struct MemoryStruct *mem = (struct MemoryStruct *)data;
mem->memory = (char *)realloc(mem->memory, mem->size + realsize + 1);
if (mem->memory)
{
memcpy(&(mem->memory[mem->size]), ptr, realsize);
mem->size += realsize;
mem->memory[mem->size] = 0;
}
return realsize;
}
上传文件:
bool MyrCurl::httpRequestWithFile(const QString strUrl, const STHttpFileData mutiFileData, QJsonObject &jsonResult)
{
bool bSuccess = false;
CURL *pCurl = curl_easy_init();
if( nullptr == pCurl)
{
bSuccess = false;
return bSuccess;
}
curl_easy_setopt(pCurl, CURLOPT_POST, 1); // post req
curl_easy_setopt(pCurl, CURLOPT_TIMEOUT, 3L);//请求超时时长
curl_easy_setopt(pCurl, CURLOPT_CONNECTTIMEOUT, 10L); //连接超时时长
curl_easy_setopt(pCurl, CURLOPT_FOLLOWLOCATION, 1L);//允许重定向
curl_easy_setopt(pCurl, CURLOPT_HEADER, 0L); //若启用,会将头文件的信息作为数据流输出
curl_easy_setopt(pCurl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); //得到请求结果后的回调函数
MemoryStruct oDataChunk; //请求结果的保存格式
curl_easy_setopt(pCurl, CURLOPT_WRITEDATA, &oDataChunk);
curl_easy_setopt(pCurl, CURLOPT_NOSIGNAL, 1L); //关闭中断信号响应
curl_easy_setopt(pCurl, CURLOPT_VERBOSE, 1L); //启用时会汇报所有的信息
curl_easy_setopt(pCurl, CURLOPT_URL, strUrl.toStdString().c_str() ); //需要获取的URL地址
curl_slist *pList = nullptr;
pList = curl_slist_append(pList,"Connection:keep-alive");
pList = curl_slist_append(pList,"multipart/form-data");
curl_easy_setopt(pCurl, CURLOPT_HTTPHEADER, pList);
struct curl_httppost *formpost = nullptr;
struct curl_httppost *lastptr = nullptr;
//发送文件的参数
curl_formadd(&formpost, &lastptr, CURLFORM_PTRNAME, "messageId", CURLFORM_PTRCONTENTS, mutiFileData.messageId.data(), CURLFORM_END);
curl_formadd(&formpost, &lastptr, CURLFORM_PTRNAME, "startNum", CURLFORM_PTRCONTENTS, mutiFileData.startNum.data(), CURLFORM_END);
curl_formadd(&formpost, &lastptr, CURLFORM_PTRNAME, "sendState", CURLFORM_PTRCONTENTS, mutiFileData.sendState.data(), CURLFORM_END);
curl_formadd(&formpost, &lastptr, CURLFORM_PTRNAME, "file", CURLFORM_BUFFER, "",
CURLFORM_BUFFERPTR, mutiFileData.multipartFile.data(),
CURLFORM_BUFFERLENGTH, mutiFileData.multipartFile.length(),
CURLFORM_CONTENTTYPE, "file", CURLFORM_END);//参数不能缺少任何一个
curl_easy_setopt(pCurl, CURLOPT_HTTPPOST, formpost);
QDateTime dateTime;
qDebug() << "sendData begin:" << dateTime.currentDateTime().toString("hh-mm-ss");
CURLcode res = curl_easy_perform(pCurl); //执行请求
qDebug() << "sendData end:" << dateTime.currentDateTime().toString("hh-mm-ss");
long res_code = 0;
res = curl_easy_getinfo(pCurl, CURLINFO_RESPONSE_CODE, &res_code);
//正确响应后,请请求转写成本地文件的文件
if(( res == CURLE_OK ) && (res_code == 200 || res_code == 201))
{
qDebug() << "result:" << ar;
}
curl_slist_free_all(pList);
curl_easy_cleanup(pCurl);
return bSuccess;
}
- 请求数据:
bool MyrCurl::httpRequestWithJson(const QString strUrl, const QJsonObject &jsonPara, QJsonObject &jsonResult)
{
bool bSuccess = false;
CURL *pCurl = curl_easy_init();
if( nullptr == pCurl)
{
bSuccess = false;
return bSuccess;
}
curl_easy_setopt(pCurl, CURLOPT_POST, 1); // post req
curl_easy_setopt(pCurl, CURLOPT_TIMEOUT, 3L);//请求超时时长
curl_easy_setopt(pCurl, CURLOPT_CONNECTTIMEOUT, 10L); //连接超时时长
curl_easy_setopt(pCurl, CURLOPT_FOLLOWLOCATION, 1L);//允许重定向
curl_easy_setopt(pCurl, CURLOPT_HEADER, 0L); //若启用,会将头文件的信息作为数据流输出
curl_easy_setopt( pCurl, CURLOPT_SSL_VERIFYPEER, false ); //设定为不验证证书和HOST
curl_easy_setopt( pCurl, CURLOPT_SSL_VERIFYHOST, false );
curl_easy_setopt(pCurl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); //得到请求结果后的回调函数
// 设置要POST的JSON数据
QString arData
QJsonDocument doc(jsonPara);
if (!jsonPara.isEmpty())
{
arData = QString(doc.toJson(QJsonDocument::Compact));
}
std::string strData = arData.toStdString();
curl_easy_setopt(pCurl, CURLOPT_POSTFIELDS, strData.data());
curl_easy_setopt(pCurl, CURLOPT_POSTFIELDSIZE, strData.length());
MemoryStruct oDataChunk; //请求结果的保存格式
curl_easy_setopt(pCurl, CURLOPT_WRITEDATA, &oDataChunk);
curl_easy_setopt(pCurl, CURLOPT_NOSIGNAL, 1L); //关闭中断信号响应
curl_easy_setopt(pCurl, CURLOPT_VERBOSE, 1L); //启用时会汇报所有的信息
curl_easy_setopt(pCurl, CURLOPT_URL, strUrl.toStdString().c_str() ); //需要获取的URL地址
curl_slist *pList = nullptr;
pList = curl_slist_append(pList,"Connection:keep-alive");
pList = curl_slist_append(pList,"Content-Type:application/json;charset=UTF-8");
curl_easy_setopt(pCurl, CURLOPT_HTTPHEADER, pList);
CURLcode res = curl_easy_perform(pCurl); //执行请求
long res_code = 0;
res = curl_easy_getinfo(pCurl, CURLINFO_RESPONSE_CODE, &res_code);
//正确响应后,请请求转写成本地文件的文件
if(( res == CURLE_OK ) && (res_code == 200 || res_code == 201))
{
qDebug() << "success" << oDataChunk.memory;
}
curl_slist_free_all(pList);
curl_easy_cleanup(pCurl);
reurn bSuccess;
}