• libcurl 工具类


    一、前言

    前一篇 【C++开源库】VS2019 编译 libcurl 库 编译除了 libcurl 库,现在来介绍下 libcurl 的使用。

    在基于 LibCurl 的程序里,主要采用 callback function (回调函数)的形式完成传输任务,用户在启动传输前设置好各类参数和回调函数,当满足条件时 libcurl 将调用用户的回调函数实现特定功能。下面是利用 libcurl 完成传输任务的流程:

    1、调用 curl_global_init() 初始化 libcurl

    2、调用 curl_easy_init() 函数得到 easy interface 型指针

    3、调用 curl_easy_setopt() 设置传输选项

    4、根据 curl_easy_setopt() 设置的传输选项,实现回调函数以完成用户特定任务

    5、调用 curl_easy_perform() 函数完成传输任务

    6、调用 curl_easy_cleanup() 释放内存

    在整个过程中设置 curl_easy_setopt() 参数是最关键的,几乎所有的 libcurl 程序都要使用它。

    get 的示例代码如下:

    #include <QDebug>
    #include <cstring>
    #include <curl/curl.h>
    
    // curl 读取到的数据保存到 std::string
    size_t curlSaveResponseToStdString(void *contents, size_t size, size_t nmemb, std::string *s) {
        size_t newLength = size * nmemb;
        size_t oldLength = s->size();
        s->resize(oldLength + newLength);
        std::copy((char*)contents, (char*)contents+newLength, s->begin()+oldLength);
    
        return size * nmemb;
    }
    
    int main(int argc, char *argv[]) {
        // 初始化 curl
        CURL *curl = curl_easy_init();
    
        if (curl) {
            std::string response;
            curl_easy_setopt(curl, CURLOPT_URL, "http://www.qtdebug.com/html/data.json"); // 设置要访问的网址
            curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlSaveResponseToStdString); // 告诉 curl 保存响应到 string 中
            curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); // 请求的响应保存到变量 response 中
            curl_easy_setopt(curl, CURLOPT_VERBOSE, 0L); // 0 不输出请求的详细信息,1 输出
            CURLcode code = curl_easy_perform(curl);
    
            if (code == CURLE_OK) {
                // std::cout << response << std::endl; // 中文乱码,因为 std::string 对中文的支持不好
                // qDebug() << QString::fromUtf8(response.data()); // response.data() 返回的是 UTF-8 的字节数据
                qDebug() << QString::fromStdString(response); // 使用 qDebug() 输出,UTF-8 的中文不会乱码
            }
        } else {
            qDebug() << "Error";
        }
    
        // 释放 curl 资源
        curl_easy_cleanup(curl);
    
        return 0;
    }
    

    至于 curl 的更多使用请参考:C++ 用libcurl库进行http通讯网络编程

    下面封装一个 libcurl 工具类。

    二、libcurl 工具类

    VS 创建个工程,添加 libcurl 的 include 和 lib 路径,再添加 libcurl_a.lib。这里新添加个 libcurl 工具类以封装,暂时只先实现 get 和 post 操作。

    CurlUtil.h

    #pragma once
    #include <string>
    #include <iostream>
    #include <list>
    #include <curl/curl.h>
    
    // libcurl工具类
    class CurlUtil
    {
    public:
    	static CurlUtil& Get() {
    		static CurlUtil m_curlUtil;
    		return m_curlUtil;
    	}
    
    	// 执行 HTTP GET 请求
    	std::string get(const char* url, CURLcode* code = NULL, std::list<const char*> headers = std::list<const char*>());
    	// 执行 HTTP POST 请求
    	std::string post(const char* url, const char* data = NULL, bool jsonBody = false, CURLcode* code = NULL, std::list<const char*> headers = std::list<const char*>());
    
    private:
    	CurlUtil();
    
    	// curl 读取到的数据保存到 std::string
    	static size_t curlSaveResponseToStdString(void* contents, size_t size, size_t nmemb, std::string* s);
    };
    

    CurlUtil.cpp

    #include "CurlUtil.h"
    
    
    
    CurlUtil::CurlUtil()
    {
    }
    
    // curl 读取到的数据保存到 std::string
    size_t CurlUtil::curlSaveResponseToStdString(void* contents, size_t size, size_t nmemb, std::string* s) {
        size_t newLength = size * nmemb;
        size_t oldLength = s->size();
        s->resize(oldLength + newLength);
        std::copy((char*)contents, (char*)contents + newLength, s->begin() + oldLength);
    
        return size * nmemb;
    }
    
    /**
     * @brief 执行 HTTP GET 请求
     * @param url  请求的 URL
     * @param code 请求返回的状态码的指针
     * @param headers 请求头
     * @return 请求执行成功时返回响应的字符串,失败则返回空字符串,请求是否执行成功可以通过 code 进行判断
     */
    std::string CurlUtil::get(const char* url, CURLcode* code, std::list<const char*> headers) {
        std::string response;
    
        // 初始化 curl
        CURL* curl = curl_easy_init();
    
        if (curl) {
            struct curl_slist* tempHeaders = NULL;
    
            std::list<const char*>::const_iterator iter;
            for (iter = headers.cbegin(); iter != headers.cend(); ++iter) {
                tempHeaders = curl_slist_append(tempHeaders, *iter);
            }
    
            curl_easy_setopt(curl, CURLOPT_HTTPHEADER, tempHeaders);
            curl_easy_setopt(curl, CURLOPT_URL, url);
            curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlSaveResponseToStdString);
            curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
            curl_easy_setopt(curl, CURLOPT_VERBOSE, 0);
    
            CURLcode temp = curl_easy_perform(curl);
    
            if (code != NULL) {
                *code = temp;
            }
    
            curl_slist_free_all(tempHeaders); /* free the header list */
        }
        else {
            if (code != NULL) {
                *code = CURLE_FAILED_INIT;
            }
        }
    
        // 释放 curl 资源
        curl_easy_cleanup(curl);
    
        return response;
    }
    
    /**
     * @brief 执行 HTTP POST 请求
     * @param url  请求的 URL
     * @param data 请求的参数
     * @param jsonBody 如果为 true,则请求的参数是 JSON 格式,否则为 Form 表单的格式 key1=value1&key2=value2&...
     * @param code 请求返回的状态码的指针
     * @param headers 请求头
     * @return 请求执行成功时返回响应的字符串,失败则返回空字符串,请求是否执行成功可以通过 code 进行判断
     */
    std::string CurlUtil::post(const char* url, const char* data, bool jsonBody, CURLcode* code, std::list<const char*> headers) {
        std::string response;
    
        // 初始化 curl
        CURL* curl = curl_easy_init();
    
        if (curl) {
            // Headers
            struct curl_slist* tempHeaders = NULL;
    
            std::list<const char*>::const_iterator iter;
            for (iter = headers.cbegin(); iter != headers.cend(); ++iter) {
                tempHeaders = curl_slist_append(tempHeaders, *iter);
            }
    
            if (jsonBody) {
                tempHeaders = curl_slist_append(tempHeaders, "Accept: application/json; charset=utf-8");
                tempHeaders = curl_slist_append(tempHeaders, "Content-Type: application/json");
            }
    
            curl_easy_setopt(curl, CURLOPT_HTTPHEADER, tempHeaders);
            curl_easy_setopt(curl, CURLOPT_URL, url);
            curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlSaveResponseToStdString);
            curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
            curl_easy_setopt(curl, CURLOPT_POST, 1); // POST 请求
            curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); // POST 参数
    
            CURLcode temp = curl_easy_perform(curl);
    
            if (code != NULL) {
                *code = temp;
            }
    
            curl_slist_free_all(tempHeaders); /* free the header list */
        }
        else {
            if (code != NULL) {
                *code = CURLE_FAILED_INIT;
            }
        }
    
        // 释放 curl 资源
        curl_easy_cleanup(curl);
    
        return response;
    }
    

    main.cpp

    #include "CurlUtil.h"
    
    int main(int argc, char* argv[]) {
    
        std::string r1 = CurlUtil::Get().get("http://qtdebug.com/html/data.json");
        std::cout << r1;
    
        std::cout << "------------------------------------------------";
    
        std::string r2 = CurlUtil::Get().post("http://eplatform.edu-edu.com.cn/live/api/auth/login", "{ "username": "u1", "password": "abcd"}", true);
        std::cout << r2;
    
        std::cout << "------------------------------------------------";
    
        CURLcode code;
        std::string r3 = CurlUtil::Get().get("http://eplatform.edu-edu.com.cn/live/api/channels/mine", &code, { "Authorization: JWT eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjU4NjM1Y2Y4NGY0N2M4MGYyNGI1NDQ5NyIsImlhdCI6MTUwOTA3NjY5MCwiZXhwIjoxNTA5MTYzMDkwfQ.6nLBnhjTYJgwjwFf_Lf0LreKryrQ6ITdT-PcGAPhKB8" });
        std::cout << r3;
    
        return 0;
    }
    

    参考:

    Qt 使用 curl


  • 相关阅读:
    洛谷 1195 口袋的天空
    洛谷1955 程序自动分析
    【洛谷3295】[SCOI2016]萌萌哒
    洛谷2024 食物链
    八数码问题
    Codeforces Round #442 (Div. 2)
    Oracle 中truncate与delete的区别
    git命令提交步骤和解决冲突的
    git 更新代码到本地
    12、Python中的包
  • 原文地址:https://www.cnblogs.com/linuxAndMcu/p/14725423.html
Copyright © 2020-2023  润新知