【QT常用技术讲解】发送POST包(两种方式:阻塞方式及非阻塞方式)

前言

        http/https(应用层)协议是广泛使用的网络通信协议。在很多与第三方API对接的场景中,通常是通过http/https协议完成,比如API对接时,通常要通过POST包获取access_token进行鉴权,然后再进行数据交互(本篇也包含有对接收数据的json数据解析代码)。

        本篇以百度AI的API接口的access_token鉴权为例,通过QT特性QNetworkAccessManager实现两种方式的POST包方式:阻塞方式和非阻塞方式。

功能讲解

阻塞方式

        QT开发的工具,通常没有高并发的网络通信服务需求,类似原生socket一样,send完数据之后就(阻塞方式)recv数据,这是非常普遍的调用方式,以下展示调用百度AI的API鉴权接口的过程。

//头文件networkmanager.h
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QEventLoop>
#include <QUrl>
#include <QUrlQuery>
#include <QJsonDocument>
#include <QJsonObject>
#include <QObject>
#include <QDebug>
#define API_KEY "GU1GeuGXNDhG48Z2aMYE2rD1"
#define SECRET_KEY "NxrnIMZ7hi8vfIT734SiLhmwCpStEN8K"

class NetworkManager : public QObject
{
    Q_OBJECT
public:
    explicit NetworkManager(QObject *parent = nullptr);
    QByteArray  block_post_data(const QNetworkRequest& request,const QUrlQuery& postData);
    QString get_access_token(const QString& client_id,const QString& client_secret) ;
};


//cpp文件networkmanager.cpp
#include "networkmanager.h"

NetworkManager::NetworkManager(QObject *parent) : QObject(parent)
{

}

QByteArray NetworkManager::block_post_data(const QNetworkRequest& request,const QUrlQuery& postData){
    //QString resstr;
    QByteArray responseData;
    // 创建网络访问管理器
    QNetworkAccessManager block_manager;//这里不要用QNetworkAccessManager *block_manager的方式
    // 发送POST请求
    QNetworkReply* reply = block_manager.post(request, postData.toString(QUrl::FullyEncoded).toUtf8());

    // 创建一个事件循环来阻塞当前线程
    QEventLoop loop;
    QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
    // 阻塞当前线程直到网络请求完成
    loop.exec();
    // 检查请求结果
    if (reply->error() == QNetworkReply::NoError) {
        // 请求成功,处理返回的数据
        /*QByteArray */responseData = reply->readAll();
        //resstr = QString::fromUtf8(responseData);
        //qDebug() << __LINE__ <<"Response:" << resstr;
    } else {
        // 请求失败,处理错误
        qDebug() << "Error:" << reply->errorString();
        responseData="";
    }
    // 清理
    reply->deleteLater();
    return responseData;
}


QString NetworkManager::get_access_token(const QString& client_id,const QString& client_secret) {
    QString access_token;
    QUrl url("https://aip.baidubce.com/oauth/2.0/token");
    QNetworkRequest request(url);
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
    request.setRawHeader("Accept", "application/json");

    // 创建 POST 数据
    QUrlQuery postData;
    postData.addQueryItem("grant_type", "client_credentials");
    postData.addQueryItem("client_id", client_id);
    postData.addQueryItem("client_secret", client_secret);

    //发送Post包(通过阻塞方式获取返回结果)
    QByteArray jsonData=block_post_data(request,postData);
    // 解析 JSON 数据
    QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData);
    if (jsonDoc.isNull()) {
        qDebug() << "Failed to create JSON doc.";
        return "";
    }
    // 检查 JSON 文档类型
    if (jsonDoc.isObject()) {
        QJsonObject jsonObj = jsonDoc.object();
        //qDebug() << "JSON Object:" << jsonObj;
        // 访问 JSON 对象中的数据
        if (jsonObj.contains("access_token")) {
            access_token = jsonObj["access_token"].toString();
            qDebug() << "access_token:" << access_token;
        }
    } else {
        qDebug() << "JSON is not an object.";
    }
    return access_token;
}


//主函数文件main.cpp
#include "networkmanager.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    NetworkManager networkManager;
    QString access_token=networkManager.get_access_token(API_KEY,SECRET_KEY);
    return a.exec();
}

以上代码中,调用QNetworkAccessManager的post之后,通过循环事件来阻塞线程,直到获取到结果(QNetworkReply::finished)之后,才退出事件循环(QEventLoop::quit)。

    // 创建一个事件循环来阻塞当前线程
    QEventLoop loop;
    QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
    // 阻塞当前线程直到网络请求完成
    loop.exec();

除此之外,源代码还包含了json解析部分,因为只有一个层级,直接获取access_token字段的内容即可。

// 解析 JSON 数据
    QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData);
    if (jsonDoc.isNull()) {
        qDebug() << "Failed to create JSON doc.";
        return "";
    }
    // 检查 JSON 文档类型
    if (jsonDoc.isObject()) {
        QJsonObject jsonObj = jsonDoc.object();
        //qDebug() << "JSON Object:" << jsonObj;
        // 访问 JSON 对象中的数据
        if (jsonObj.contains("access_token")) {//-----json格式中最外层的access_token字段
            access_token = jsonObj["access_token"].toString();
            qDebug() << "access_token:" << access_token;
        }
    } else {
        qDebug() << "JSON is not an object.";
    }

非阻塞方式

        在设计时,如果异步处理更加符合框架的处理性能需求时,比如鉴权完成之后,批量调用百度AI的OCR接口时,批量的组装并发送POST包,然后异步的接收数据之后,保存到本地(或者是抽取关键数据)的场景时,就得用异步的方式,以下只是展示调用百度AI的API鉴权接口来贴源代码。

//头文件networkmanager.h
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QUrl>
#include <QByteArray>
#include <QUrlQuery>
#include <QJsonDocument>
#include <QJsonObject>
#include <QObject>
#include <QDebug>

#define API_KEY "GU1GeuGXNDhG48Z2aMYE2rD1"
#define SECRET_KEY "NxrnIMZ7hi8vfIT734SiLhmwCpStEN8K"

class NetworkManager : public QObject
{
    Q_OBJECT
public:
    explicit NetworkManager(QObject *parent = nullptr);
    void get_access_token(const QString& client_id,const QString& client_secret) ;
private slots:
    void onFinished(QNetworkReply *reply);

private:
    QNetworkAccessManager *manager;
};

--------------------------------------------------------------------------

//cpp文件networkmanager.cpp
#include "networkmanager.h"

NetworkManager::NetworkManager(QObject *parent) : QObject(parent)
{
    manager = new QNetworkAccessManager(this);
    connect(manager, &QNetworkAccessManager::finished, this, &NetworkManager::onFinished);//接收数据的槽函数
}


void NetworkManager::get_access_token(const QString& client_id,const QString& client_secret) {
    QUrl url("https://aip.baidubce.com/oauth/2.0/token");
    QNetworkRequest request(url);
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
    request.setRawHeader("Accept", "application/json");

    // 创建 POST 数据
    QUrlQuery postData;
    postData.addQueryItem("grant_type", "client_credentials");
    postData.addQueryItem("client_id", client_id);
    postData.addQueryItem("client_secret", client_secret);

    // 发送 POST 请求
    //manager->post(request, jsonData);
    // 发送 POST 请求
    manager->post(request, postData.toString(QUrl::FullyEncoded).toUtf8());

}


void NetworkManager::onFinished(QNetworkReply *reply) {
    if (reply->error() == QNetworkReply::NoError) {
        QByteArray responseData = reply->readAll();
        qDebug() << "Response:" << responseData;
    } else {
        qDebug() << "Error:" << reply->errorString();
    }
    reply->deleteLater();
}


//主函数main.cpp
#include <QApplication>
#include "networkmanager.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    NetworkManager networkManager;
    networkManager.get_access_token(API_KEY,SECRET_KEY);

    return a.exec();
}

源码中通过信号和槽机制,统一获取并处理Post的返回结果。

//通过信号和槽机制,统一获取并处理Post的返回结果
manager = new QNetworkAccessManager(this);
connect(manager, &QNetworkAccessManager::finished, this, &NetworkManager::onFinished);

void NetworkManager::onFinished(QNetworkReply *reply) {
    if (reply->error() == QNetworkReply::NoError) {
        QByteArray responseData = reply->readAll();
        qDebug() << "Response:" << responseData;
    } else {
        qDebug() << "Error:" << reply->errorString();
    }
    reply->deleteLater();
}

片尾

        因为百度API是https调用的,QT环境需要专门匹配的SSL版本来支持,如果没有对应的动态文件,编译时会如下报错:

以下提供一个传送门:

解决qt.network.ssl 和 OpenSSL 1.1.1g Win64版本EXE下载

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/941400.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

重撸设计模式--代理模式

文章目录 定义UML图代理模式主要有以下几种常见类型&#xff1a;代理模式涉及的主要角色有&#xff1a;C 代码示例 定义 代理模式&#xff08;Proxy Pattern&#xff09;属于结构型设计模式&#xff0c;它为其他对象提供一种代理以控制对这个对象的访问。 通过引入代理对象&am…

【Steel Code】 10.5 COMPOSITE COLUMNS

10.5 COMPOSITE COLUMNS 组合柱 10.5.1 General 总则 (1) This clause applies for the design of composite columns and composite compression members with fully encased H sections, partially encased H sections, and infilled rectangular and circular hollow sect…

11.vector的介绍及模拟实现

1.vector的介绍 记得之前我们用C语言实现过顺序表&#xff0c;vector本质上也是顺序表&#xff0c;一个能够动态增长的数组。 vector 的底层实现机制 - 动态数组&#xff1a;vector 的底层实现是动态数组。它在内存中连续存储元素&#xff0c;就像一个可以自动调整大小的数…

封装(2)

大家好&#xff0c;今天我们来介绍一下包的概念&#xff0c;知道包的作用可以更好的面对今后的开发&#xff0c;那么我们就来看看包是什么东西吧。 6.3封装扩展之包 6.3.1包的概念 在面向对象体系中,提出了一个软件包的概念,即:为了更好的管理类,把多个类收集在一起成为一组…

go官方日志库带色彩格式化

go默认的 log 输出的日志样式比较难看&#xff0c;所以通过以下方式进行了美化和格式化&#xff0c;而且加入了 unicode 的ascii码&#xff0c;进行色彩渲染。 package mainimport ("fmt""log""os""runtime""strings""…

0基础学前端系列 -- 深入理解 HTML 布局

在现代网页设计中&#xff0c;布局是至关重要的一环。良好的布局不仅能提升用户体验&#xff0c;还能使内容更具可读性和美观性。HTML&#xff08;超文本标记语言&#xff09;结合 CSS&#xff08;层叠样式表&#xff09;为我们提供了多种布局方式。本文将详细介绍流式布局、Fl…

Windows开启IIS后依然出现http error 503.the service is unavailable

问题背景 已启用IIS服务&#xff0c;配置步骤可以参考Windows10 IIS Web服务器安装配置 问题描述 在这一步浏览网站时&#xff0c;并没有出现默认首页&#xff0c;而是 http error 503 the service is unavailable 问题解决 参考 成功解决http error 503.the service is un…

BuildCTF 公开赛web部分wp

文章目录 LovePopChainRedFlagWhy_so_serials?babyuploadeazyl0ginez!httpez_md5find-the-idsubtflock刮刮乐我写的网站被rce了&#xff1f; LovePopChain payload: <?php class MyObject{public $NoLove"Do_You_Want_Fl4g?";public $Forgzy;public functi…

diff 算法实现的几种方法和前端中的应用

diff 算法原理和几种实现方法 diff 是什么 diff 算法就是比较两个数据的差异&#xff0c;例如字符串的差异&#xff0c;对象的差异。 常用于版本管理&#xff08;git&#xff09;例如下面的实际案例。 github 上某个 commit&#xff0c;旧代码和新代码之间的不同 diff 展示…

Nacos源码搭建

拉取并配置代码 仓库地址 https://github.com/alibaba/nacos找到config 模块中找到 \resources\META-INF\mysql-schema.sql&#xff0c;在本地mysql中创建数据库nacos-config&#xff0c;将该脚本导入执行创建表。 找到console模块下的配置文件application.properties&#x…

C# Winfrom chart图 实例练习

代码太多了我就不展示了&#xff0c;贴一些比较有代表性的 成品效果展示&#xff1a; Excel转Chart示例 简单说一下我的思路 \ 先把Excel数据展示在dataGridView控件上 XLIST 为 X轴的数据 XLIST 为 Y轴的数据 ZLIST 为 展示的数据进行数据处理点击展示即可 // 将Excel数…

# 起步专用 - 哔哩哔哩全模块超还原设计!(内含接口文档、数据库设计)

↑ 上方下载文档 (大小374KB) 接口文档预览 (超过50个接口) 一、数据库25张表er-关系清晰构图&#xff01;(tip: 鼠标右键图片 > 放大图像) 二、难点/经验 详细说明 热门评论排序评论点赞列表|DTO封装经验分享|精华接口文档说明 组员都说喜欢分档对应枚举码 如果这篇文章…

【Go学习】从一个出core实战问题看Go interface赋值过程

0x01 背景 版本中一个同学找我讨论一个服务出core的问题&#xff0c;最终他靠自己的探索解决了问题&#xff0c;给出了初步的直接原因结论&#xff0c;"Go 中 struct 赋值不是原子的”。间接原因的分析是准确的&#xff0c;直接原因&#xff0c;我有点怀疑。当时写了一些…

leetcode之hot100---54螺旋矩阵(C++)

思路一&#xff1a;模拟 模拟螺旋矩阵的路径&#xff0c;路径超出界限&#xff0c;顺时针旋转&#xff0c;使用一个数组记录当前数字是否被访问到&#xff0c;直到所有的数字全部被访问 class Solution {//一个静态的常量数组&#xff0c;用于标记螺旋矩阵的移动方向(行列变化…

新能源汽车锂离子电池各参数的时间序列关系

Hi&#xff0c;大家好&#xff0c;我是半亩花海。为了进一步开展新能源汽车锂离子电池的相关研究&#xff0c;本文主要汇总并介绍了电动汽车的锂离子电池的各项参数&#xff0c;通过 MATLAB 软件对 Oxford Dataset 的相关数据集进行数据处理与分析&#xff0c;进一步研究各项参…

FastStone 10.x 注册码

简介 FastStone Capture是一款经典好用的屏幕截图软件&#xff0c;在屏幕截图领域具有广泛的应用和众多优势。 软件基本信息 FastStone Capture体积小巧&#xff0c;占用内存少&#xff0c;这使得它在运行时不会给计算机系统带来过多的负担&#xff0c;即使在配置较低的电脑…

AI合成图片是什么意思?有什么用?

随着人工智能的发展&#xff0c;现在市面上出现了很多对企业帮助很大的AI工具&#xff0c;比如说AI合成图片、AI换模特、AI穿衣、AI图片设计等等&#xff0c;下面小编就以AI合成图片为例&#xff0c;为大家详细介绍下。 一、AI合成图片是什么意思? AI合成图片主要就是指利用人…

【示例】Vue AntV G6 base64自定义img 动画效果,自适应宽高屏

需求&#xff1a;拓扑图中需要用动画的线条连接node&#xff0c;在此之前将HTML页面改成了vue页面。需要使用到G6的registerEdge 自定义边&#xff0c;小车的图片需要转成base64格式&#xff08;并翻转&#xff09;&#xff0c;可以通过base64转image查看原来的样子。 另外&am…

MySQL的分析查询语句

【图书推荐】《MySQL 9从入门到性能优化&#xff08;视频教学版&#xff09;》-CSDN博客 《MySQL 9从入门到性能优化&#xff08;视频教学版&#xff09;&#xff08;数据库技术丛书&#xff09;》(王英英)【摘要 书评 试读】- 京东图书 (jd.com) MySQL9数据库技术_夏天又到了…

【递归,搜索与回溯算法 综合练习】深入理解暴搜决策树:递归,搜索与回溯算法综合小专题(二)

优美的排列 题目解析 算法原理 解法 &#xff1a;暴搜 决策树 红色剪枝&#xff1a;用于剪去该节点的值在对应分支中&#xff0c;已经被使用的情况&#xff0c;可以定义一个 check[ ] 紫色剪枝&#xff1a;perm[i] 不能够被 i 整除&#xff0c;i 不能够被 per…