curl操作之Get/Post/上传文件 参数设置以及调用细节

  • Curl初始化参数
    // 这个接口里面设置的参数选项已经完全覆盖了 Get、Post、HttpPost(文件上传)操作    
    int HttpClient::initCurl(const HttpClientUrlArgs &urlArgs) {
        auto headers = urlArgs.headers;
        std::vector<std::string> ips;
        if (XXX::XXX::GetInstance().GetProxyConfigInfo().m_httpDnsEnable) {
            ips = XXX::XXX::GetInstance().GetIpsByHostName(urlArgs.hostName);
        }

        if (ips.empty()) {
            m_requestUrl = XXX::SplicingUrl(urlArgs.protocol, urlArgs.hostName, urlArgs.port, urlArgs.url, urlArgs.args);
        } else {
            m_requestUrl = XXX::SplicingUrl(urlArgs.protocol, ips[RandomNum()%ips.size()], urlArgs.port, urlArgs.url, urlArgs.args);
            headers.emplace("Host", urlArgs.hostName);
        }

        if (m_pCurl != nullptr) {
            curl_easy_cleanup(m_pCurl);
            m_pCurl = nullptr;
        }
        if (m_pHeadList != nullptr) {
            curl_slist_free_all(m_pHeadList);
            m_pHeadList = nullptr;
        }

        m_pCurl = curl_easy_init();
        if (m_pCurl == nullptr) {
            return -1;
        }

        curl_easy_setopt(m_pCurl, CURLOPT_URL, m_requestUrl.c_str()); // 请求地址
        curl_easy_setopt(m_pCurl, CURLOPT_ACCEPT_ENCODING, "");
        curl_easy_setopt(m_pCurl, CURLOPT_NOSIGNAL, 1L);
        curl_easy_setopt(m_pCurl, CURLOPT_TIMEOUT, 10L);
        curl_easy_setopt(m_pCurl, CURLOPT_SSL_VERIFYHOST, 0L);
        curl_easy_setopt(m_pCurl, CURLOPT_SSL_VERIFYPEER, false);
        curl_easy_setopt(m_pCurl, CURLOPT_WRITEFUNCTION, HttpClientOnWriteCallback); // 写回调:如Post、HttpPost
        curl_easy_setopt(m_pCurl, CURLOPT_WRITEDATA, this);
        curl_easy_setopt(m_pCurl, CURLOPT_READFUNCTION, HttpClientOnReadCallback); // 读回调:如Get
        curl_easy_setopt(m_pCurl, CURLOPT_READDATA, this);
        curl_easy_setopt(m_pCurl, CURLOPT_MAXREDIRS, 10L);
        curl_easy_setopt(m_pCurl, CURLOPT_FOLLOWLOCATION, 1L);
        curl_easy_setopt(m_pCurl, CURLOPT_NOPROGRESS, 0L);
        curl_easy_setopt(m_pCurl, CURLOPT_DNS_USE_GLOBAL_CACHE, 0L);
        curl_easy_setopt(m_pCurl, CURLOPT_PROGRESSDATA, this);
        curl_easy_setopt(m_pCurl, CURLOPT_PROGRESSFUNCTION, HttpClientOnProgressCallback);
        curl_easy_setopt(m_pCurl, CURLOPT_FAILONERROR, 1L);

        m_pHeadList = curl_slist_append(m_pHeadList, "Expect:");
        if (!headers.empty()) {
            for (const auto& it : headers) {
                auto tmp = it.first + ": " + it.second;
                m_pHeadList = curl_slist_append(m_pHeadList, tmp.c_str());
            }
        }

        curl_easy_setopt(m_pCurl, CURLOPT_HTTPHEADER, m_pHeadList);
        return 0;
    }
  • 上传文件核心参数
    int HttpClient::OnProgressCallback(double dt, double dn, double ult, double uln) {
        if (m_isExit != nullptr && m_isExit()) {
            return -1;
        }
        return 0;
    }
    
    // 读回调
    size_t HttpClient::OnReadCallback(void *buffer, size_t size, size_t nmemb, void *arg){
        return nmemb*size;
    }

    // 写回调
    size_t HttpClient::OnWriteCallback(void *buffer, size_t size, size_t nmemb, void *arg) {
        if (buffer != nullptr && size > 0 && nmemb > 0) {
            m_result.append((char*)buffer, size*nmemb);
        }
        return size*nmemb;
    }

    // 获取必要的参数 具体看需求
    void HttpClient::UpdateInfo() {
        if (m_pCurl == nullptr) {
            return;
        }
        double dnsTime = 0;
        if (curl_easy_getinfo(m_pCurl, CURLINFO_NAMELOOKUP_TIME, &dnsTime) == CURLE_OK) {
            m_iDnsTime = dnsTime*1000;
        }
        long code = 0;
        if (curl_easy_getinfo(m_pCurl, CURLINFO_RESPONSE_CODE, &code) == CURLE_OK) {
            m_iCurlCode = code;
        }
        char *ip = nullptr;
        if ((curl_easy_getinfo(m_pCurl, CURLINFO_PRIMARY_IP, &ip) == CURLE_OK) && (ip != nullptr)) {
            m_remoteIp = ip;
        }
        double temp = 0.0;
        const unsigned int k_dwThousand = 1000;
        if (curl_easy_getinfo(m_pCurl, CURLINFO_TOTAL_TIME, &temp) == CURLE_OK) {
            m_interactionTime.dwTotalTime = (uint32_t)(temp * k_dwThousand);
        }
        if (curl_easy_getinfo(m_pCurl, CURLINFO_NAMELOOKUP_TIME, &temp) == CURLE_OK) {
            m_interactionTime.dwNameLookupTime = (uint32_t)(temp * k_dwThousand);
        }
        if (curl_easy_getinfo(m_pCurl, CURLINFO_CONNECT_TIME, &temp) == CURLE_OK) {
            m_interactionTime.dwConnectTime = (uint32_t)(temp * k_dwThousand);
        }
        if (curl_easy_getinfo(m_pCurl, CURLINFO_PRETRANSFER_TIME, &temp) == CURLE_OK) {
            m_interactionTime.dwPretransferTime = (uint32_t)(temp * k_dwThousand);
        }
        if (curl_easy_getinfo(m_pCurl, CURLINFO_FILETIME, &m_interactionTime.lFileTime) == CURLE_OK) {
            
        }
        if (curl_easy_getinfo(m_pCurl, CURLINFO_STARTTRANSFER_TIME, &temp) == CURLE_OK) {
            m_interactionTime.dwStartTransferTime = (uint32_t)(temp * k_dwThousand);
        }
        if (curl_easy_getinfo(m_pCurl, CURLINFO_REDIRECT_TIME, &temp) == CURLE_OK) {
            m_interactionTime.dwRedirectTime = (uint32_t)(temp * k_dwThousand);
        }
        if (curl_easy_getinfo(m_pCurl, CURLINFO_APPCONNECT_TIME, &temp) == CURLE_OK) {
            m_interactionTime.dwAppconnetTime = (uint32_t)(temp * k_dwThousand);
        }
    }

    // Get操作
    int HttpClient::GetData(std::string &result, const HttpClientUrlArgs &urlArgs) {
        if (initCurl(urlArgs) != 0) {
            xerror2(TSF"init curl error!");
            return -1;
        }

        m_result.clear();
        auto res = curl_easy_perform(m_pCurl);
        if (res != CURLE_OK) {
            xerror2(TSF"url: %_, res: %_", m_requestUrl.c_str(), res);
        }

        result.clear();
        result = std::move(m_result);
        UpdateInfo();
        return res;
    }

    // Post操作
    int HttpClient::PostData(std::string &result, const HttpClientUrlArgs &urlArgs, const std::string &content) {
        result.clear();
        if (initCurl(urlArgs) != 0) {
            xerror2(TSF"init curl error!");
            return -1;
        }
        curl_easy_setopt(m_pCurl, CURLOPT_POST, true);
        curl_easy_setopt(m_pCurl, CURLOPT_POSTFIELDS, content.c_str());
        m_result.clear();
        auto res = curl_easy_perform(m_pCurl);
        if (res != CURLE_OK) {
            xerror2(TSF"url: %_, res: %_", m_requestUrl.c_str(), res);
        }
        result = std::move(m_result);
        UpdateInfo();
        return res;
    }

    // 上传文件操作
    int HttpClient::PostBinaryData(std::string &result, const HttpClientUrlArgs &urlArgs, const std::string &filePath, const std::string &fileName) {
                if (initCurl(urlArgs) != 0) {
            xerror2(TSF"init curl error!");
            return -1;
        }

        if (m_pFormpost != nullptr) {
            curl_formfree(m_pFormpost);
            m_pFormpost = nullptr;
        }

        struct curl_httppost *lastPtr = nullptr;
        // 注意参数顺序, 这块踩过坑; 之前因为参数顺序问题查了好久
        curl_formadd(&m_pFormpost, &lastPtr, CURLFORM_PTRNAME, "log_file", CURLFORM_FILENAME, fileName.c_str(), CURLFORM_FILE, filePath.c_str(), CURLFORM_END);
        
        // 跟服务端定 需要什么字段, 就如下写法加什么字段
        curl_formadd(&m_pFormpost, &lastPtr, CURLFORM_PTRNAME, "client_id", CURLFORM_PTRCONTENTS, XXX.c_str(), CURLFORM_END);
        curl_easy_setopt(m_pCurl, CURLOPT_HTTPPOST, m_pFormpost);


        m_result.clear();
        auto res = curl_easy_perform(m_pCurl);
        if (res != CURLE_OK) {
            xerror2(TSF"curl easy perform error, url: %_, res: %_", m_requestUrl.c_str(), res);
            return res;
        }

        // 获取WriteCallBack中的结果信息来判断这次执行是否成功以及查询出错原因
        result = std::move(m_result);
        UpdateInfo();
        return 0;
    }
  • 外部调用核心参数
    // 上传文件部分调用核心代码
    HttpClientUrlArgs urlArgs;
    ...
    // Content-Type格式——上传文件
    urlArgs.headers["Content-Type"] = "multipart/form-data";

    // Content-Type格式——Post字符串
    urlArgs.headers["Content-Type"] = "text/plain"; // 一般是内存中字符串, 如日志上传
    urlArgs.headers["Content-Type"] = "application/json"; // 默认的json格式

    // Content-Type格式——Get操作
    urlArgs.headers["Content-Type"] = 可以不指定这个字段, 走默认"application/json";
    
    // 注意: Curl提供了客户线程退出标识检查机制(新版本废弃)
    int HttpClient::OnProgressCallback(double dt, double dn, double ult, double uln) {
        if (m_isExit != nullptr && m_isExit()) {
            return -1;
        }
        return 0;
    }
    
    // 如下设置回调isExit标识当前线程是否退出
    ...
    std::shared_ptr<HttpClient> httpClient = std::make_shared<HttpClient>(XXX::bind(&XXX::isExit, this));
    ...

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值