一、前言
前一篇 【C++开源库】VS2019 编译 libcurl 库 编译除了 libcurl 库,现在来介绍下 libcurl 的使用。
在基于 LibCurl 的程序里,主要采用 callback function (回调函数)的形式完成传输任务,用户在启动传输前设置好各类参数和回调函数,当满足条件时 libcurl 将调用用户的回调函数实现特定功能。下面是利用 libcurl 完成传输任务的流程:
- 调用 curl_global_init() 初始化 libcurl
- 调用 curl_easy_init() 函数得到 easy interface 型指针
- 调用 curl_easy_setopt() 设置传输选项
- 根据 curl_easy_setopt() 设置的传输选项,实现回调函数以完成用户特定任务
- 调用 curl_easy_perform() 函数完成传输任务
- 调用 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;
}
参考: