使用C++和libcurl库实现HTTP请求(GET、POST、文件上传)
在现代软件开发中,与外部API服务进行通信已成为常见需求。本文将展示如何使用C++和libcurl
库实现基本的HTTP请求,包括GET请求、POST请求(带JSON数据)以及包含文件上传的POST请求。
准备工作
首先,需要确保已安装libcurl
库,并正确链接到项目中。如果还没有安装libcurl
,可以在libcurl官网找到安装方法。使用CMake构建项目时,可以在CMakeLists.txt
中指定库路径,确保CURL能够找到:
# set(CMAKE_PREFIX_PATH "${CMAKE_SOURCE_DIR}/libcurl/share/curl") # 替换为 CURL 安装的实际路径
find_package(CURL REQUIRED)
target_link_libraries(your_project_name PRIVATE CURL::libcurl)
基本结构
代码的核心是三个函数,分别用于GET请求、带JSON的POST请求和包含文件上传的POST请求。每个函数使用了libcurl
的不同配置来处理具体需求。
代码结构和功能实现
1. req_reply
:处理请求响应的函数
这个函数是libcurl
的回调函数,用于处理从服务器返回的数据,将数据写入到指定的字符串流中。
size_t req_reply(void *ptr, size_t size, size_t nmemb, void *stream) {string *str = (string *) stream;(*str).append((char *) ptr, size * nmemb);return size * nmemb;
}
2. GET 请求
GET请求是最常用的请求类型,用于从服务器获取资源。curl_get_req
函数实现了GET请求,通过curl_easy_setopt
函数来设置URL和请求参数。
CURLcode curl_get_req(const std::string &url, std::string &response) {CURL *curl = curl_easy_init();CURLcode res;if (curl) {curl_easy_setopt(curl, CURLOPT_URL, url.c_str());curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); // 忽略SSL证书验证curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply);curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) &response);curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);res = curl_easy_perform(curl);curl_easy_cleanup(curl);}return res;
}
3. 发送带JSON数据的POST请求
POST请求通常用于将数据发送到服务器,尤其是RESTful API。curl_post_json
函数可以发送包含JSON数据的POST请求,代码通过设置Content-Type
头为application/json
来指定数据类型。
CURLcode curl_post_json(const string &url, const string &jsonData, string &response) {CURL *curl = curl_easy_init();CURLcode res;if (curl) {struct curl_slist *headers = NULL;headers = curl_slist_append(headers, "Content-Type: application/json");curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);curl_easy_setopt(curl, CURLOPT_POST, 1);curl_easy_setopt(curl, CURLOPT_URL, url.c_str());curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsonData.c_str());curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply);curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) &response);res = curl_easy_perform(curl);curl_slist_free_all(headers);curl_easy_cleanup(curl);}return res;
}
4. 发送包含JSON和文件的POST请求
在某些情况下,我们可能需要同时发送JSON数据和文件。这里用curl_mime
实现多部分表单上传。curl_mime
允许将JSON数据和文件字段一起打包并发送给服务器。
CURLcode curl_post_with_file(const string &url, const string &jsonData, const string &filePath, string &response) {CURL *curl = curl_easy_init();CURLcode res;if (curl) {struct curl_slist *headers = NULL;headers = curl_slist_append(headers, "Content-Type: multipart/form-data");curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);// 创建 MIME 表单curl_mime *form = curl_mime_init(curl);// 添加 JSON 数据字段curl_mimepart *jsonField = curl_mime_addpart(form);curl_mime_name(jsonField, "json");curl_mime_data(jsonField, jsonData.c_str(), CURL_ZERO_TERMINATED);curl_mime_type(jsonField, "application/json");// 添加文件字段curl_mimepart *fileField = curl_mime_addpart(form);curl_mime_name(fileField, "file");curl_mime_filedata(fileField, filePath.c_str());curl_mime_type(fileField, "image/png");curl_easy_setopt(curl, CURLOPT_URL, url.c_str());curl_easy_setopt(curl, CURLOPT_MIMEPOST, form);curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply);curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) &response);res = curl_easy_perform(curl);curl_mime_free(form);curl_slist_free_all(headers);curl_easy_cleanup(curl);}return res;
}
测试用例
最后,我们在main
函数中展示了三个测试用例,分别是GET请求、带JSON数据的POST请求和带文件的POST请求。
#include <iostream>
#include <string>
#include "curl/curl.h"using namespace std;// 请求的回复处理函数
size_t req_reply(void *ptr, size_t size, size_t nmemb, void *stream) {string *str = (string *) stream;(*str).append((char *) ptr, size * nmemb);return size * nmemb;
}// HTTP GET 请求
CURLcode curl_get_req(const std::string &url, std::string &response) {CURL *curl = curl_easy_init();CURLcode res;if (curl) {// 设置 URL 地址curl_easy_setopt(curl, CURLOPT_URL, url.c_str());// 设置忽略 SSL 证书验证curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);// 设置回复处理函数curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply);curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) &response);curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);curl_easy_setopt(curl, CURLOPT_HEADER, 1);// 设置连接和响应超时时间curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);res = curl_easy_perform(curl); // 执行 GET 请求curl_easy_cleanup(curl); // 清理 curl 资源}return res;
}// 发送带有 JSON 数据的 HTTP POST 请求
CURLcode curl_post_json(const string &url, const string &jsonData, string &response) {CURL *curl = curl_easy_init();CURLcode res;if (curl) {struct curl_slist *headers = NULL;headers = curl_slist_append(headers, "Content-Type: application/json"); // 设置 JSON 类型头部// headers = curl_slist_append(headers, ("appcode: " + appcode).c_str());// headers = curl_slist_append(headers, ("User-Agent: " + agent).c_str());curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);// 设置 POST 请求参数curl_easy_setopt(curl, CURLOPT_POST, 1);curl_easy_setopt(curl, CURLOPT_URL, url.c_str());curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsonData.c_str());curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply);curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) &response);curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);curl_easy_setopt(curl, CURLOPT_HEADER, 1);curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);res = curl_easy_perform(curl); // 执行 POST 请求curl_slist_free_all(headers); // 释放头部内存curl_easy_cleanup(curl); // 清理 curl 资源}return res;
}// 发送包含 JSON 数据和文件的 POST 请求
CURLcode curl_post_with_file(const string &url, const string &jsonData, const string &filePath, string &response) {CURL *curl = curl_easy_init();CURLcode res;if (curl) {struct curl_slist *headers = NULL;headers = curl_slist_append(headers, "Content-Type: multipart/form-data"); // 设置多部分表单头部curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);// 创建 MIME 表单curl_mime *form = curl_mime_init(curl);// 添加 JSON 数据字段curl_mimepart *jsonField = curl_mime_addpart(form);curl_mime_name(jsonField, "json");curl_mime_data(jsonField, jsonData.c_str(), CURL_ZERO_TERMINATED);curl_mime_type(jsonField, "application/json");// 添加文件字段curl_mimepart *fileField = curl_mime_addpart(form);curl_mime_name(fileField, "file");curl_mime_filedata(fileField, filePath.c_str());curl_mime_type(fileField, "image/png"); // 设置文件类型为 image/png// 设置 CURL 参数curl_easy_setopt(curl, CURLOPT_URL, url.c_str());curl_easy_setopt(curl, CURLOPT_MIMEPOST, form);curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply);curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) &response);curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10);// 执行请求res = curl_easy_perform(curl);// 清理 MIME 表单和头部curl_mime_free(form);curl_slist_free_all(headers);curl_easy_cleanup(curl);}return res;
}int main() {curl_global_init(CURL_GLOBAL_ALL);// 测试 GET 请求string getUrlStr = "http://cn.bing.com/images/trending?form=Z9LH";string getResponseStr;auto res = curl_get_req(getUrlStr, getResponseStr);if (res != CURLE_OK)cerr << "GET 请求失败: " + string(curl_easy_strerror(res)) << endl;elsecout << getResponseStr << endl;// JSON POST 请求string postUrlStr = "https://api.example.com/endpoint";string jsonData = R"({"key1": "value1", "key2": "value2"})";string postResponseStr;res = curl_post_json(postUrlStr, jsonData, postResponseStr);if (res != CURLE_OK)cerr << "POST 请求失败: " + string(curl_easy_strerror(res)) << endl;elsecout << postResponseStr << endl;// JSON 和文件的 POST 请求string postfileStr = "https://api.example.com/upload";string filePath = "path/to/image.png"; // 指定上传的文件路径res = curl_post_with_file(postfileStr, jsonData, filePath, postResponseStr);if (res != CURLE_OK)cerr << "文件 POST 请求失败: " + string(curl_easy_strerror(res)) << endl;elsecout << "服务器响应:\n" << postResponseStr << endl;// 清空curl_global_cleanup();system("pause");return 0;
}
总结
使用libcurl
实现HTTP请求是与外部API或服务器进行通信的强大工具。本文展示了如何发送GET请求、带JSON数据的POST请求以及包含文件的POST请求,涵盖了许多实际应用中的需求。通过合理配置libcurl
选项,可以轻松实现高效且可靠的网络请求。
相关文章:
使用C++和libcurl库实现HTTP请求(GET、POST、文件上传)
在现代软件开发中,与外部API服务进行通信已成为常见需求。本文将展示如何使用C和libcurl库实现基本的HTTP请求,包括GET请求、POST请求(带JSON数据)以及包含文件上传的POST请求。 准备工作 首先,需要确保已安装libcur…...
makefile例子
$指代当前目标,就是Make命令当前构建的那个目标。比如,make foo的 $ 就指代foo。 $< 指代第一个前置条件。比如,规则为 t: p1 p2,那么$< 就指代p1。 $? 指代比目标更新的所有前置条件,之间以空格分隔。比如&a…...

用环形数组实现队列(多种高级方法,由浅入深)
同普通数组实现的队列相比,普通数组的头结点和尾节点都是固定的,在进行移除的时候如果移除了一个节点,后面所有节点都需要进行移除操作,需要的时间复杂度更高 在环形数组中,确定了头尾指针的环形数组很好地解决了这一…...
springboot框架使用RabbitMQ举例代码
以前分享过一个理论有兴趣的小伙伴可以看下 https://blog.csdn.net/Drug_/article/details/138164180 不多说 还是直接上代码 第一步:引入依赖 可以不指定版本 <!-- amqp --><dependency><groupId>org.springframework.boot</groupId…...
Java实现一个延时队列
文章目录 前言正文一、基本概念1.1 延时队列的特点1.2 常见的实现方式 二、Java原生的内存型延时队列2.1 定义延时元素DelayedElement2.2 定义延时队列管理器DelayedQueueManager2.3 消费元素2.4 调试2.5 调试结果2.6 精髓之 DelayQueue.poll() 三、基于Redisson的延时队列3.1 …...
为什么说vue是双向数据流
Vue.js 被称为 双向数据绑定(two-way data binding),是因为它支持数据在 视图(View) 和 模型(Model) 之间双向流动。这意味着,当 数据变化 时,视图会自动更新;…...

创造属于你的 Claude Prompt 和个性化 SVG 卡片|对李继刚老师提示词的浅浅解析与总结
❤️ 如果你也关注大模型与 AI 的发展现状,且对大模型应用开发非常感兴趣,我会快速跟你分享最新的感兴趣的 AI 应用和热点信息,也会不定期分享自己的想法和开源实例,欢迎关注我哦! 🥦 微信公众号ÿ…...
redis与本地缓存
本地缓存是将数据存储在应用程序所在的本地内存中的缓存方式。既然,已经有了 Redis 可以实现分布式缓存了,为什么还需要本地缓存呢?接下来,我们一起来看。 为什么需要本地缓存? 尽管已经有 Redis 缓存了,但…...
git撤销commit和add
撤销commit git reset --soft HEAD^撤销add git reset .查看状态 git status...

【361】基于springboot的招生宣传管理系统
摘 要 使用旧方法对招生宣传管理系统的信息进行系统化管理已经不再让人们信赖了,把现在的网络信息技术运用在招生宣传管理系统的管理上面可以解决许多信息管理上面的难题,比如处理数据时间很长,数据存在错误不能及时纠正等问题。这次开发的招…...
【一些关于Python的信息和帮助】
Python是一种广泛使用的高级编程语言,它的设计哲学强调代码的可读性和简洁的语法(尤其是使用空格缩进划分代码块,而不是使用大括号或关键字)。Python支持多种编程范式,包括面向对象、命令式、函数式和过程式编程。 以…...

creo toolkit二次开发学习之程序集(ProAsmcomp)和装配体组件路径对象(ProAsmcomppath)
程序集ProAsmcomp可以理解为装配体组件对象。 对象ProAssembly是ProSolid的一个实例,并共享相同的声明。因此,ProAssembly对象可以作为适用于装配体的任何ProSolid和ProMdl函数的输入。特别是,因为你可以使用函数ProSolidFeatVisit()来遍历特…...

深入浅出 Spring Boot 与 Shiro:构建安全认证与权限管理框架
一、Shiro框架概念 (一)Shiro框架概念 1.概念: Shiro是apache旗下一个开源安全框架,它对软件系统中的安全认证相关功能进行了封装,实现了用户身份认证,权限授权、加密、会话管理等功能,组成一…...

外包干了三年,精神严重内耗...
前段时间我同事(做测试的一个妹子)跟我讲,感觉早上起来十分的疲惫,不想上班,问我们这是什么样的现象,其实有时候我也有这种感觉,虽然我卷,但我也是肉体凡胎啊!不是机器人…...

ruoyi-vue集成tianai-captcha验证码
后端代码 官方使用demo文档:http://doc.captcha.tianai.cloud/#%E4%BD%BF%E7%94%A8demo 我的完整代码:https://gitee.com/Min-Duck/RuoYi-Vue.git 主pom.xml 加入依赖 <!-- 滑块验证码 --><dependency><groupId>cloud.tianai.captc…...

Django安装
在终端创建django项目 1.查看自己的python版本 输入对应自己本机python的版本,列如我的是3.11.8 先再全局安装django依赖包 2.在控制窗口输入安装命令: pip3.11 install django 看到Successflully 说明我们就安装成功了 python的Scripts文件用于存…...

Ubuntu 20.04 安装 QGC v4.3 开发环境
Ubuntu 20.04 安装 QGC开发环境 1. 准备安装 Qt 5.15.2安装依赖获取源码 2. 编译参考 前言 QGC ( QGroundControl) 是一个开源地面站,基于QT开发的,有跨平台的功能。可以在Windows,Android,MacOS或Linux上运行。它可以将PX4固件加…...

WPF+MVVM案例实战(二十一)- 制作一个侧边弹窗栏(AB类)
文章目录 1、案例效果1、侧边栏分类2、AB类侧边弹窗实现1.文件创建2、样式代码与功能代码实现3、功能代码实现 3 运行效果4、源代码获取 1、案例效果 1、侧边栏分类 A类 :左侧弹出侧边栏B类 :右侧弹出侧边栏C类 :顶部弹出侧边栏D类 …...
linux中怎样登录mysql数据库
在Linux中登录MySQL数据库,可以使用以下命令: mysql -u username -p 其中,username是你的MySQL用户名。运行该命令后,系统会提示你输入密码。 如果MySQL服务器不在本地主机或者你需要指定不同的端口,可以使用以下命…...
深入理解 Linux 内存管理:free 命令详解
在 Linux 系统中,内存是关键的资源之一,管理和监控内存的使用情况对系统的稳定性和性能至关重要。free 命令是 Linux 中用于查看内存使用情况的重要工具,它可以让我们快速了解系统中物理内存和交换分区(Swap)的使用状态…...

(十)学生端搭建
本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...

SpringTask-03.入门案例
一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...
QT3D学习笔记——圆台、圆锥
类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体(对象或容器)QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质(定义颜色、反光等)QFirstPersonC…...
Java求职者面试指南:计算机基础与源码原理深度解析
Java求职者面试指南:计算机基础与源码原理深度解析 第一轮提问:基础概念问题 1. 请解释什么是进程和线程的区别? 面试官:进程是程序的一次执行过程,是系统进行资源分配和调度的基本单位;而线程是进程中的…...

RSS 2025|从说明书学习复杂机器人操作任务:NUS邵林团队提出全新机器人装配技能学习框架Manual2Skill
视觉语言模型(Vision-Language Models, VLMs),为真实环境中的机器人操作任务提供了极具潜力的解决方案。 尽管 VLMs 取得了显著进展,机器人仍难以胜任复杂的长时程任务(如家具装配),主要受限于人…...

倒装芯片凸点成型工艺
UBM(Under Bump Metallization)与Bump(焊球)形成工艺流程。我们可以将整张流程图分为三大阶段来理解: 🔧 一、UBM(Under Bump Metallization)工艺流程(黄色区域ÿ…...