一、前言
前一篇 【C++开源库】VS2019 编译 libcurl 库 编译除了 libcurl 库,现在来介绍下 libcurl 的使用。
在基于 LibCurl 的程序里,主要采用 callback function (回调函数)的形式完成传输任务,用户在启动传输前设置好各类参数和回调函数,当满足条件时 libcurl 将调用用户的回调函数实现特定功能。下面是利用 libcurl 完成传输任务的流程:
在整个过程中设置 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 工具类。
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