当前位置: 首页 > news >正文

使用 C/C++ 调用 libcurl 调试消息

        在使用 C/C++ 调用 libcurl 进行 HTTP 请求时,有时我们需要查看请求的/应答消息的内容(包括请求头和请求体)以方便调试。libcurl 提供了多种方法来捕获和输出这些信息,本文介绍具体的使用方式。


1. libcurl 调试工具简介

  libcurl 是一个功能强大的库,用于在 C/C++ 中实现 HTTP 请求(支持 GET、POST、PUT 等方法)。为了调试请求和响应信息,libcurl 提供了以下功能:

  • 启用详细日志输出: 使用 CURLOPT_VERBOSE 打印所有传输信息。
  • 自定义调试回调函数: 使用 CURLOPT_DEBUGFUNCTION 捕获并处理调试日志。
  • 输出请求头和请求体: 使用 CURLINFO_HEADER_OUTCURLOPT_POSTFIELDS 输出完整的请求。
  • 捕获响应内容: 使用 CURLOPT_WRITEFUNCTION 将服务器响应保存到变量中。

2. 输出请求消息

  • 使用 CURLOPT_VERBOSE

CURLOPT_VERBOSE 是最简单的调试工具,通过设置该选项为 1L,可以让 libcurl 输出详细的传输信息,包括请求头和请求体:

curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);

输出内容示例如下:

> POST /api HTTP/1.1
> Host: example.com
> Content-Type: application/json
> Content-Length: 29
>
* upload completely sent off: 29 out of 29 bytes
  • 使用 CURLOPT_DEBUGFUNCTION

        如果需要对调试信息进行更多控制,可以使用 CURLOPT_DEBUGFUNCTION 自定义处理逻辑,例如将日志保存到文件或字符串中。

以下是自定义调试回调函数的代码:

#include <iostream>
#include <string>
#include <curl/curl.h>int DebugCallback(CURL* handle, curl_infotype type, char* data, size_t size, void* userptr) {std::string* log = static_cast<std::string*>(userptr);if (type == CURLINFO_HEADER_OUT) {log->append("[REQUEST HEADERS]:\n");log->append(data, size);} else if (type == CURLINFO_DATA_OUT) {log->append("[REQUEST BODY]:\n");log->append(data, size);}return 0;
}

3. 输出响应消息

为了捕获服务器的响应,可以使用 CURLOPT_WRITEFUNCTION 将响应保存到变量中:

size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* userp) {size_t totalSize = size * nmemb;userp->append((char*)contents, totalSize);return totalSize;
}

在配置 CURL 选项时,添加:

curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &responseString);

4. 完整代码示例

以下是一个完整的示例,展示如何使用 libcurl 发送 HTTPS POST 请求,并输出请求和响应的详细信息。

#include <iostream>
#include <string>
#include <curl/curl.h>// 自定义调试回调函数
int DebugCallback(CURL* handle, curl_infotype type, char* data, size_t size, void* userptr) {std::string* log = static_cast<std::string*>(userptr);if (type == CURLINFO_HEADER_OUT) {log->append("[REQUEST HEADERS]:\n");log->append(data, size);} else if (type == CURLINFO_DATA_OUT) {log->append("[REQUEST BODY]:\n");log->append(data, size);}return 0;
}// 回调函数:接收服务器的响应数据
size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* userp) {size_t totalSize = size * nmemb;userp->append((char*)contents, totalSize);return totalSize;
}int main() {CURL* curl = curl_easy_init();if (!curl) {std::cerr << "Failed to initialize CURL!" << std::endl;return 1;}const std::string url = "https://example.com/api";const std::string jsonData = R"({"key1":"value1", "key2":"value2"})";std::string responseString;std::string debugLog;  // 用于存储调试日志struct curl_slist* headers = nullptr;headers = curl_slist_append(headers, "Content-Type: application/json");// 设置 CURL 选项curl_easy_setopt(curl, CURLOPT_URL, url.c_str());curl_easy_setopt(curl, CURLOPT_POST, 1L);curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsonData.c_str());curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);curl_easy_setopt(curl, CURLOPT_WRITEDATA, &responseString);// 启用调试功能curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, DebugCallback);curl_easy_setopt(curl, CURLOPT_DEBUGDATA, &debugLog);// 执行请求CURLcode res = curl_easy_perform(curl);if (res != CURLE_OK) {std::cerr << "CURL error: " << curl_easy_strerror(res) << std::endl;} else {std::cout << "Response: " << responseString << std::endl;}// 输出调试日志std::cout << "\n===== Debug Log =====\n" << debugLog << std::endl;curl_easy_cleanup(curl);curl_slist_free_all(headers);return 0;
}

5. 编译和运行

  • 确保已安装 libcurl。 在 Ubuntu 上安装:

    sudo apt-get install libcurl4-openssl-dev
    
  • 使用以下命令编译代码:

    g++ -o post_debug post_debug.cpp -lcurl
    
  • 运行程序:

    ./post_debug
    

6. 输出示例

程序运行后,会输出请求和响应信息,例如:

调试日志

===== Debug Log =====
[REQUEST HEADERS]:
POST /api HTTP/1.1
Host: example.com
Content-Type: application/json
Content-Length: 29[REQUEST BODY]:
{"key1":"value1", "key2":"value2"}

响应内容

Response: {"status":"success","message":"Data received"}

总结

通过启用 CURLOPT_VERBOSE 或自定义 CURLOPT_DEBUGFUNCTION,可以轻松查看 libcurl 的请求消息(包括请求头和请求体)。结合响应回调函数,能完整调试 HTTP 请求和服务器返回的内容。这些工具对于开发和调试网络程序非常有用!

相关文章:

使用 C/C++ 调用 libcurl 调试消息

在使用 C/C 调用 libcurl 进行 HTTP 请求时&#xff0c;有时我们需要查看请求的/应答消息的内容&#xff08;包括请求头和请求体&#xff09;以方便调试。libcurl 提供了多种方法来捕获和输出这些信息&#xff0c;本文介绍具体的使用方式。 1. libcurl 调试工具简介 libcurl 是…...

【愚公系列】《循序渐进Vue.js 3.x前端开发实践》030-自定义组件的插槽Mixin

标题详情作者简介愚公搬代码头衔华为云特约编辑&#xff0c;华为云云享专家&#xff0c;华为开发者专家&#xff0c;华为产品云测专家&#xff0c;CSDN博客专家&#xff0c;CSDN商业化专家&#xff0c;阿里云专家博主&#xff0c;阿里云签约作者&#xff0c;腾讯云优秀博主&…...

大一计算机的自学总结:异或运算

前言 异或运算这个操作看上去很匪夷所思&#xff0c;实际上作用非常大。 一、异或运算的性质 1.异或运算就是无进位相加。 2.满足交换律、结合律。 3.0^nn&#xff0c;n^n0。 4.若集合B为集合A子集&#xff0c;集合A异或和为x&#xff0c;集合B异或和为y&#xff0c;则集…...

通过protoc工具生成proto的pb.go文件以及使用protoc-go-inject-tag工具注入自定义标签

1.ProtoBuf认识,安装以及用法 参考:[golang 微服务] 3. ProtoBuf认识&#xff0c;安装以及golang 中ProtoBuf使用 2. 使用protoc-go-inject-tag工具注入自定义标签 这里有一个案例: syntaxproto3; package test;option go_package ".;test";message MyMessage {int6…...

C语言练习(29)

13个人围成一圈&#xff0c;从第1个人开始顺序报号1、2、3。凡报到“3”者退出圈子&#xff0c;找出最后留在圈子中的人原来的序号。本题要求用链表实现。 #include <stdio.h> #include <stdlib.h>// 定义链表节点结构体 typedef struct Node {int num;struct Nod…...

Android实训九 数据存储和访问

实训9 数据存储和访问 一、【实训目的】 1、 SharedPreferences存储数据; 2、 借助Java的I/O体系实现文件的存储&#xff0c; 3、使用Android内置的轻量级数据库SQLite存储数据; 二、【实训内容】 1、实现下图所示的界面&#xff0c;实现以下功能&#xff1a; 1&#xff…...

实验一---典型环节及其阶跃响应---自动控制原理实验课

一 实验目的 1.掌握典型环节阶跃响应分析的基本原理和一般方法。 2. 掌握MATLAB编程分析阶跃响应方法。 二 实验仪器 1. 计算机 2. MATLAB软件 三 实验内容及步骤 利用MATLAB中Simulink模块构建下述典型一阶系统的模拟电路并测量其在阶跃响应。 1.比例环节的模拟电路 提…...

SOME/IP--协议英文原文讲解2

前言 SOME/IP协议越来越多的用于汽车电子行业中&#xff0c;关于协议详细完全的中文资料却没有&#xff0c;所以我将结合工作经验并对照英文原版协议做一系列的文章。基本分三大块&#xff1a; 1. SOME/IP协议讲解 2. SOME/IP-SD协议讲解 3. python/C举例调试讲解 4.1 Speci…...

matlab中,fill命令用法

在 MATLAB 中&#xff0c;fill 命令用于创建填充多边形的图形对象。使用 fill 可以在二维坐标系中绘制填充的区域&#xff0c;通常用于绘制图形的背景或显示数据分布。 基本语法 fill(X, Y, C)X 和 Y 是同样长度的向量&#xff0c;定义了多边形的顶点坐标。C 是颜色&#xff0…...

【Linux】Linux C判断两个IPv6地址是否有包含关系

功能说明 要判断两个 IPv6 地址是否具有包含关系&#xff0c;包括前缀的比较&#xff0c;可以通过以下步骤实现&#xff1a; 解析 IPv6 地址和前缀&#xff1a;将两个 IPv6 地址和它们的前缀长度解析为二进制形式。生成掩码&#xff1a;根据前缀长度生成掩码。按位比较&#…...

【玩转全栈】----Django基本配置和介绍

目录 Django基本介绍&#xff1a; Django基本配置&#xff1a; 安装Django 创建项目 创建app 注册app Django配置路由URL Django创建视图 启动项目 Django基本介绍&#xff1a; Django是一个开源的、基于Python的高级Web框架&#xff0c;旨在以快速、简洁的方式构建高质量的Web…...

mysql 学习6 DML语句,对数据库中的表进行 增 删 改 操作

添加数据 我们对 testdatabase 数据中 的 qqemp 这张表进行 增加数据&#xff0c;在这张表 下 打开 命令行 query console 在 软件中就是打开命令行的意思 可以先执行 desc qqemp; 查看一下当前表的结构。 插入一条数据 到qqemp 表&#xff0c;插入时要每个字段都有值 insert…...

自动化运维在云环境中的完整实践指南

随着云计算的普及,越来越多的企业将业务迁移到云上。云环境的高动态性和复杂性使得传统的手动运维方式难以应对,自动化运维成为提升效率、降低成本、保障系统稳定性的关键。本文将详细介绍如何在云环境中实施自动化运维,涵盖工具选择、实施步骤和最佳实践。 © ivwdcwso…...

一分钟搭建promehteus+grafana+alertmanager监控平台

为什么要自己搭建一个监控平台 平时进行后端开发&#xff0c;特别是微服务的后端可开发&#xff0c;一定少不了对接监控平台&#xff0c;但是平时进行一些小功能的测试又没有必要每次都手动安装那么多软件进行一个小功能的测试&#xff0c;这里我使用docker-compose搭建了一个…...

【10.2】队列-设计循环队列

一、题目 设计你的循环队列实现。 循环队列是一种线性数据结构&#xff0c;其操作表现基于 FIFO&#xff08;先进先出&#xff09;原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。 循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普…...

设置jmeter界面图标字体大小

设置jmeter界面图标字体大小 方法&#xff1a;点击“选项” -> 点击放大、缩小。&#xff08;可进行全局的菜单、左侧目录结构树、元件界面显示等字体图标的放大、缩小。&#xff09;...

Xposed-Hook

配置 Xposed 模块的 AndroidManifest.xml&#xff1a; <?xml version"1.0" encoding"utf-8"?> <manifest xmlns:android"http://schemas.android.com/apk/res/android"package"your.package.name"><applicationandr…...

设计模式Python版 原型模式

文章目录 前言一、原型模式二、原型模式示例三、原型管理器 前言 GOF设计模式分三大类&#xff1a; 创建型模式&#xff1a;关注对象的创建过程&#xff0c;包括单例模式、简单工厂模式、工厂方法模式、抽象工厂模式、原型模式和建造者模式。结构型模式&#xff1a;关注类和对…...

QT:图像上绘制图形

需求描述 1、展示一张图像 2、在图像上可以使用数据绘制图像&#xff1a;矩形、不规则图形、线条 3、有按键可以选择 概要设计 规划布局如下 1、左边是Qlabel 用于展示图片 2、右边是三个按钮 具体实现 1、 首先设计 UI 界面&#xff0c;对控件进行布局 在 mainwindow.u…...

GPU上没程序在跑但是显存被占用

原因&#xff1a;存在僵尸线程&#xff0c;运行完但是没有释放内存 查看僵尸线程 fuser -v /dev/nvidia*关闭僵尸线程 pkill -9 -u 用户名 程序名 举例&#xff1a;pkill -9 -u grs python参考&#xff1a;https://blog.csdn.net/qq_40206371/article/details/143798866...

Python:操作 Excel 折叠

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地

借阿里云中企出海大会的东风&#xff0c;以**「云启出海&#xff0c;智联未来&#xff5c;打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办&#xff0c;现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...

【解密LSTM、GRU如何解决传统RNN梯度消失问题】

解密LSTM与GRU&#xff1a;如何让RNN变得更聪明&#xff1f; 在深度学习的世界里&#xff0c;循环神经网络&#xff08;RNN&#xff09;以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而&#xff0c;传统RNN存在的一个严重问题——梯度消失&#…...

C++.OpenGL (14/64)多光源(Multiple Lights)

多光源(Multiple Lights) 多光源渲染技术概览 #mermaid-svg-3L5e5gGn76TNh7Lq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3L5e5gGn76TNh7Lq .error-icon{fill:#552222;}#mermaid-svg-3L5e5gGn76TNh7Lq .erro…...

深入浅出Diffusion模型:从原理到实践的全方位教程

I. 引言&#xff1a;生成式AI的黎明 – Diffusion模型是什么&#xff1f; 近年来&#xff0c;生成式人工智能&#xff08;Generative AI&#xff09;领域取得了爆炸性的进展&#xff0c;模型能够根据简单的文本提示创作出逼真的图像、连贯的文本&#xff0c;乃至更多令人惊叹的…...

如何做好一份技术文档?从规划到实践的完整指南

如何做好一份技术文档&#xff1f;从规划到实践的完整指南 &#x1f31f; 嗨&#xff0c;我是IRpickstars&#xff01; &#x1f30c; 总有一行代码&#xff0c;能点亮万千星辰。 &#x1f50d; 在技术的宇宙中&#xff0c;我愿做永不停歇的探索者。 ✨ 用代码丈量世界&…...

CppCon 2015 学习:Simple, Extensible Pattern Matching in C++14

什么是 Pattern Matching&#xff08;模式匹配&#xff09; ❝ 模式匹配就是一种“描述式”的写法&#xff0c;不需要你手动判断、提取数据&#xff0c;而是直接描述你希望的数据结构是什么样子&#xff0c;系统自动判断并提取。❞ 你给的定义拆解&#xff1a; ✴ Instead of …...

触发DMA传输错误中断问题排查

在STM32项目中&#xff0c;集成BLE模块后触发DMA传输错误中断&#xff08;DMA2_Stream1_IRQHandler进入错误流程&#xff09;&#xff0c;但单独运行BLE模块时正常&#xff0c;表明问题可能源于原有线程与BLE模块的交互冲突。以下是逐步排查与解决方案&#xff1a; 一、问题根源…...

Android多媒体——音/视频数据播放(十八)

在媒体数据完成解码并准备好之后,播放流程便进入了最终的呈现阶段。为了确保音视频内容能够顺利输出,系统需要首先对相应的播放设备进行初始化。只有在设备初始化成功后,才能真正开始音视频的同步渲染与播放。这一过程不仅影响播放的启动速度,也直接关系到播放的稳定性和用…...

MySQL 数据库深度剖析:事务、SQL 优化、索引与 Buffer Pool

在当今数据驱动的时代&#xff0c;数据库作为数据存储与管理的核心&#xff0c;其性能与可靠性至关重要。MySQL 作为一款广泛使用的开源数据库&#xff0c;在众多应用场景中发挥着关键作用。在这篇博客中&#xff0c;我将围绕 MySQL 数据库的核心知识展开&#xff0c;涵盖事务及…...