Bootstrap

curl使用

本文主要通过代码示例,详细介绍一下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;
}
;